summaryrefslogtreecommitdiff
path: root/testenv
diff options
context:
space:
mode:
Diffstat (limited to 'testenv')
-rw-r--r--testenv/ChangeLog576
-rw-r--r--testenv/Makefile.am65
-rw-r--r--testenv/Makefile.in1800
-rw-r--r--testenv/README305
-rwxr-xr-xtestenv/Test--https-crl.py50
-rwxr-xr-xtestenv/Test--https.py55
-rwxr-xr-xtestenv/Test--spider-r.py106
-rwxr-xr-xtestenv/Test-504.py72
-rwxr-xr-xtestenv/Test-Content-disposition-2.py54
-rwxr-xr-xtestenv/Test-Content-disposition.py56
-rwxr-xr-xtestenv/Test-Head.py44
-rwxr-xr-xtestenv/Test-O.py45
-rwxr-xr-xtestenv/Test-Post.py48
-rwxr-xr-xtestenv/Test-auth-basic-fail.py51
-rwxr-xr-xtestenv/Test-auth-basic.py59
-rwxr-xr-xtestenv/Test-auth-both.py77
-rwxr-xr-xtestenv/Test-auth-digest.py50
-rwxr-xr-xtestenv/Test-auth-no-challenge-url.py54
-rwxr-xr-xtestenv/Test-auth-no-challenge.py54
-rwxr-xr-xtestenv/Test-auth-retcode.py50
-rwxr-xr-xtestenv/Test-auth-with-content-disposition.py54
-rwxr-xr-xtestenv/Test-c-full.py53
-rwxr-xr-xtestenv/Test-cookie-401.py59
-rwxr-xr-xtestenv/Test-cookie-domain-mismatch.py58
-rwxr-xr-xtestenv/Test-cookie-expires.py81
-rwxr-xr-xtestenv/Test-cookie.py57
-rwxr-xr-xtestenv/Test-redirect-crash.py74
-rw-r--r--testenv/certs/README77
-rw-r--r--testenv/certs/ca-cert.pem20
-rw-r--r--testenv/certs/ca-key.pem144
-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/conf/__init__.py47
-rw-r--r--testenv/conf/__pycache__/__init__.cpython-33.pyobin0 -> 2076 bytes
-rw-r--r--testenv/conf/__pycache__/authentication.cpython-33.pyobin0 -> 839 bytes
-rw-r--r--testenv/conf/__pycache__/expect_header.cpython-33.pyobin0 -> 737 bytes
-rw-r--r--testenv/conf/__pycache__/expected_files.cpython-33.pyobin0 -> 2321 bytes
-rw-r--r--testenv/conf/__pycache__/expected_ret_code.cpython-33.pyobin0 -> 1358 bytes
-rw-r--r--testenv/conf/__pycache__/files_crawled.cpython-33.pyobin0 -> 1430 bytes
-rw-r--r--testenv/conf/__pycache__/hook_sample.cpython-33.pyobin0 -> 1041 bytes
-rw-r--r--testenv/conf/__pycache__/local_files.cpython-33.pyobin0 -> 1071 bytes
-rw-r--r--testenv/conf/__pycache__/reject_header.cpython-33.pyobin0 -> 737 bytes
-rw-r--r--testenv/conf/__pycache__/response.cpython-33.pyobin0 -> 706 bytes
-rw-r--r--testenv/conf/__pycache__/rule_sample.cpython-33.pyobin0 -> 748 bytes
-rw-r--r--testenv/conf/__pycache__/send_header.cpython-33.pyobin0 -> 721 bytes
-rw-r--r--testenv/conf/__pycache__/server_files.cpython-33.pyobin0 -> 1677 bytes
-rw-r--r--testenv/conf/__pycache__/urls.cpython-33.pyobin0 -> 904 bytes
-rw-r--r--testenv/conf/__pycache__/wget_commands.cpython-33.pyobin0 -> 1024 bytes
-rw-r--r--testenv/conf/authentication.py22
-rw-r--r--testenv/conf/expect_header.py12
-rw-r--r--testenv/conf/expected_files.py51
-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.py18
-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/__pycache__/__init__.cpython-33.pyobin0 -> 143 bytes
-rw-r--r--testenv/exc/__pycache__/server_error.cpython-33.pyobin0 -> 805 bytes
-rw-r--r--testenv/exc/__pycache__/test_failed.cpython-33.pyobin0 -> 741 bytes
-rw-r--r--testenv/exc/server_error.py7
-rw-r--r--testenv/exc/test_failed.py7
-rw-r--r--testenv/misc/__init__.py0
-rw-r--r--testenv/misc/__pycache__/__init__.cpython-33.pyobin0 -> 144 bytes
-rw-r--r--testenv/misc/__pycache__/colour_terminal.cpython-33.pyobin0 -> 1115 bytes
-rw-r--r--testenv/misc/__pycache__/wget_file.cpython-33.pyobin0 -> 850 bytes
-rw-r--r--testenv/misc/colour_terminal.py44
-rw-r--r--testenv/misc/wget_file.py16
-rw-r--r--testenv/server/__init__.py0
-rw-r--r--testenv/server/__pycache__/__init__.cpython-33.pyobin0 -> 146 bytes
-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/__pycache__/__init__.cpython-33.pyobin0 -> 151 bytes
-rw-r--r--testenv/server/http/__pycache__/http_server.cpython-33.pyobin0 -> 23082 bytes
-rw-r--r--testenv/server/http/http_server.py442
-rw-r--r--testenv/test/__init__.py0
-rw-r--r--testenv/test/__pycache__/__init__.cpython-33.pyobin0 -> 144 bytes
-rw-r--r--testenv/test/__pycache__/base_test.cpython-33.pyobin0 -> 10325 bytes
-rw-r--r--testenv/test/__pycache__/http_test.cpython-33.pyobin0 -> 2461 bytes
-rw-r--r--testenv/test/base_test.py233
-rw-r--r--testenv/test/http_test.py46
89 files changed, 5809 insertions, 0 deletions
diff --git a/testenv/ChangeLog b/testenv/ChangeLog
new file mode 100644
index 0000000..b0f81ee
--- /dev/null
+++ b/testenv/ChangeLog
@@ -0,0 +1,576 @@
+2014-11-26 Giuseppe Scrivano <gscrivan@redhat.com>
+
+ * Makefile.am (TESTS): Add Test-redirect-crash.py.
+ * Test-redirect-crash.py: New File.
+
+2014-11-26 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * Makefile.am: Removed Test-auth-both.py from XFAIL_TESTS
+
+2014-11-21 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * server/http/http_server.py: Fixed typo Blackisted to Blacklisted
+
+2014-11-19 Darshit Shah <darnir@gmail.com>
+
+ * Test-504.py: Add new test case to show how Wget handles 504 Gateway
+ Timeouts
+ * Makefile.am: Add Test-504.py to TESTS
+
+2014-11-17 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * server/http/http_server.py: allow case-insensitive auth-type,
+ send BasIc and DIgest to provoke Wget failures with turkish locales
+
+2014-11-15 Darshit Shah <darnir@gmail.com>
+
+ * certs/README: Remove trailing whitespaces
+
+2014-11-11 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * recreated the certs and the CRL file, also amended certs/README
+
+2014-11-10 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * removed certs/wget-cert.pem
+ * added certs/ca-cert.pem, certs/ca-key.pem, certs/server-cert.pem,
+ certs/server-key.pem and certs/server-crl.pem
+ * added certs/README for description how to generate the certs and keys
+ * server/http/http_server.py: amended to work with new certs/ files
+ * added Test--https-crl.py to test --crl-file
+ * Makefile.am: added Test--https-crl.py
+ * Test--https.py: use --ca-certificate of --no-check-certificates
+
+2014-10-25 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * test/base_test.py (gen_cmd_line): generate valgrind command line if requested
+ * README: amend description of VALGRIND_TESTS
+ * Makefile.am: set/export VALGRIND_TESTS
+
+2014-10-01 Darshit Shah <darnir@gmail.com>
+
+ * Makefile.am: Run the tests in Python's Optimizedmode
+ * conf/__init__.py (gen_hook): Use try..except instead of if..else
+ * misc/color_terminal.py: System and check will not change while a test is
+ run. Do not test for them on every invokation of printer()
+ * server/http/http_server.py: The ssl and re modules are required by
+ specific functions. Load them lazily
+ (HTTPSServer.__init__): Lazy load ssl module here
+ (_handler.parse_range_header): Lazy load re module here
+ (_Handler.get_rule_list): get() can return a default value. Use it
+ (_Handler.guess_type): Same
+ (_Handler.is_authorized): Unused function artefact. Remove
+ (_Handler.reject_headers): Unused function artefact. Remove
+
+2014-10-08 Darshit Shah <darnir@gmail.com>
+
+ * Makefile.am: Fix EXTRA_DIST variable for make distcheck
+ * server/http/http_server.py (HTTPServer.__init__): Fix how CERTFILE is
+ found when running make dist / make distcheck.
+
+2014-09-30 Tim Ruehsen <tim.ruehsen@gmx.de>
+
+ * test/base_test.py: Add --track-origins=yes to valgrind testing
+
+2014-08-08 Darshit Shah <darnir@gmail.com>
+
+ * conf/__init__.py: Add extra newline according to PEP8
+ * conf/{authentication,expect_header,expected_files,expected_ret_code,
+ files_crawled,hook_sample,local_files,reject_header,response,send_header,
+ server_files,urls,wget_commands}.py: Add docstrings explaining the conf file
+ and how it should be used
+ * server/http/http_server (InvalidRangeHeader): Clear TODO and eliminate
+ this exception. Use ServerError for all such purposes.
+ (_Handler): Remove reference to InvalidRangeHeader
+ (_handler.parse_range_header): User ServerError instead of InvalidRangeHeader
+ (_Handler.do_GET): Add docstring
+ (_Handler.do_POST): Add docstring. Also create an empty dict for rules if
+ no rules are supplied. Send the Location header as suggested in RFC 7231
+ (_Handler.do_PUT): Don't pop the server file already. Push it to later in ..
+ (_Handler.send_put): .. Here. If the file exists respond with a 204 No
+ Content message and pop the file for replacement. Do not send the
+ Content-Length, Content-Type headers since PUT requests should not respond
+ with data.
+ (_Handler.parse_auth_header): Fit line within 80 chars
+ (_Handler.check_response): Better visual indent
+ (_Handler.authorize_digest): Better visual indent.
+ (_Handler.expect_headers): Remove unused function
+ (_Handler.guess_type): Fix indentation
+ (HTTPd): Add newline according to PEP8 guidelines
+ (HTTPSd): Fix indentation
+ (StoppableHTTPServer): Add docstring
+ (HTTPSServer): Fix indentation
+ (WgetHTTPRequestHandler): Merge class into _handler.
+ (_Handler): Add docstring
+ (_Handler.parse_range_header): Fix indentation
+ (ServerError): Split exception into separate file ...
+ * exc/server_error.py: ... Here
+ * misc/colour_terminal.py: Add docstring, fix indentation
+ * test/base_test.py: Fix visual indent
+ * test/http_test.py: Fit within 80 char lines
+
+2014-08-04 Darshit Shah <darnir@gmail.com>
+
+ * conf/server_conf.py: Delete file. Server configuration is now done via the
+ server_conf() method.
+ * server/http/http_server.py (StppableHTTPServer.server_sett): Delete
+ method required by the above hook
+ (HTTPd.server_sett): Same
+
+2014-07-26 Darshit Shah <darnir@gmail.com>
+
+ * Test-*.py: Remove the '-d' switch from WGET_OPTIONS.
+ * test/base_test (BaseTest.gen_cmd_line): Add --debug and --no-config to the
+ list of switches passed to wget unconditionally.
+
+2014-07-23 Darshit Shah <darnir@gmail.com>
+
+ * test/base_test.py (BaseTest.gen_cmd_line): Add support for running all
+ tests through valgrind if the relevant environment variable is set
+ * conf/expected_ret_code (ExpectedRetCode.__call__): Valgrind returns error
+ code 45 when it detects a memory leak.
+ * Readme: Update with details about valgrind tests
+
+2014-07-22 Darshit Shah <darnir@gmail.com>
+
+ * (README): Remove old TODO and document SERVER_WAIT variable
+
+2014-06-22 Darshit Shah <darnir@gmail.com>
+
+ * (conf.files_crawled): diff is a set object and needs explicit str
+ conversion.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * base_test.py:
+ (CommonMethods): Rename to BaseTest.
+ (BaseTest): Implement __init__ method where the class-wide variables are
+ initialized. Also variable names like `xxx_list` is renamed to its plural
+ form, e.g. `server_list` => `servers`.
+ (BaseTest.init_test_env): Remove name argument due to its unnecessarity.
+ (BaseTest.get_test_dir): Because the path of the test directory is needed
+ in multiple methods, this method is implemented.
+ (BaseTest.get_domain_addr): Rewrite the return statement utilizing str
+ formatting (which is more Pythonic).
+ (BaseTest.get_cmd_line): Rename to gen_cmd_line. Change the variables with
+ capitcal characters to lower ones. Also, the nested for loop is rewritten
+ to a plain loop using the zip function.
+ (BaseTest.__gen_local_filesys): Rename to gen_local_fs_snapshot. Move to
+ ExpectedFiles in conf/expected_files.py and is marked as a static
+ method. Refactor to a less verbose implementation.
+ (BaseTest._check_downloaded_files): Rename to __call__ to agree with the
+ invocation in test case classes. Move to ExpectedFiles in
+ conf/expected_files.py.
+ (BaseTest.get_server_rules): Refactor to a more Pythonic form utilizing
+ dict.items() and is marked static.
+ (BaseTest.stop_server): (new method) an abstract method which should stop
+ the currently using servers.
+ (BaseTest.instantiate_server_by): (new method) an abstract method which
+ should instantiate a server instance according to the given argument.
+ (BaseTest.__enter__): (new method) method which initialize the context
+ manager
+ (BaseTest.__exit__): (new method) method that finilize the context manager
+ and deal with the exceptions during the execution of the with statement,
+ subclasses can override this method for extensibility
+ * http_test.py:
+ (HTTPTest.__init__): Add call to super.__init__. Default values of
+ pre_hook, test_params, post_hook are set to None to avoid a subtle bug of
+ Python. Argument servers is renamed to protocols.
+ (HTTPTest.Server_setup): Move to BaseTest and rename to server_setup.
+ Calls to pre_hook_call, call_test, post_hook_call are removed.
+ (HTTPTest.hook_call, pre_hook_call, call_test, post_hook_call): Move to
+ BaseTest for that both HTTP test cases and FTP test cases may use these
+ methods.
+ (HTTPTest.init_HTTP_Server, init_HTTPS_Server): Merge and rename to
+ instantiate_server_by to implement the abstract method in BaseTest.
+ (HTTPTest.stop_HTTP_Server): Rename to stop_server to implement the
+ abstract method in BaseTest. Also, pull out the part where remaining
+ requests are gathered into a new method request_remaining.
+ (BaseTest.act_retcode): Rename to ret_code because ExpectedRetCode is
+ moved out from BaseTest, so the name act_retcode is actually a bit
+ verbose.
+ * conf/expected_ret_code.py:
+ (ExpectedRetCode.__call__): Rewrite the str into a more readable form.
+ * conf/files_crawled.py:
+ (FilesCrawled.__call__): Refactor this method into a more Pythonic form
+ utilizing the zip function.
+ * conf/local_files.py:
+ (LocalFiles__call__): Rewrite this method with the recommended with
+ statement.
+ * conf/server_conf.py:
+ (ServerConf.__call__): Rewrite this method due to BaseTest.server_list is
+ renamed to BaseTest.servers.
+ * conf/server_files.py:
+ (ServerFiles.__call__): Refactor the nested for loop into a plain one
+ utilizing the zip function.
+ * conf/urls.py:
+ (URLs): Rename url_list to urls.
+ * conf/wget_commands.py:
+ (WgetCommands): Rename command_list to commands, rename test_obj.options
+ to test_obj.wget_options.
+ * Test--https.py, Test-Proto.py, Test-Parallel-Proto.py: Argument servers
+ is changed to protocols due to change in the signature of
+ HTTPTest.__init__.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * test: (new package) package for test case classes
+ * WgetTest.py: Split into test/base_test.py and test/http_test.py.
+ * Test-*.py: Optimize the imports according to changes of WgetTest.py
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * server: (new package) package for the server classes
+ * server.http: (new package) package for HTTP server
+ * server.ftp: (new package) package for FTP server
+ * HTTPServer.py: Move to server/http/http_server.py. Also change the
+ CERTFILE to '../certs/wget-cert.pem'.
+ * FTPServer.py: Move to server/ftp/ftp_server.py.
+ * WgetTest.py: Optimize import respect to the server classes.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * conf: (new package) package for rule classes and hook methods
+ * WgetTest.py:
+ (CommonMethods.Authentication): Move to conf/authentication.py.
+ (CommonMethods.ExpectHeader): Move to conf/expect_header.py.
+ (CommonMethods.RejectHeader): Move to conf/reject_header.py.
+ (CommonMethods.Response): Move to conf/response.py.
+ (CommonMethods.SendHeader): Move to conf/send_header.py.
+ (CommonMethods.ServerFiles): Move to conf/server_files.py.
+ (CommonMethods.LocalFiles): Move to conf/local_files.py.
+ (CommonMethods.ServerConf): Move to conf/server_conf.py.
+ (CommonMethods.WgetCommands): Move to conf/wget_commands.py.
+ (CommonMethods.Urls): Move to conf/urls.py.
+ (CommonMethods.ExpectedRetcode): Move to conf/expected_retcode.py.
+ (CommonMethods.ExpectedFiles): Move to conf/expected_files.py.
+ (CommonMethods.FilesCrawled): Move to conf/files_crawled.py.
+ (CommonMethods.__check_downloaded_files): Rename to
+ _check_downloaded_files, so that the method is callable from outside the
+ class.
+ (CommomMethods.get_server_rules): Modify so that it utilizes the conf
+ package.
+ (HTTPTest): Add a method hook_call(configs, name) to reduce duplications
+ in pre_hook_call, call_test and post_hook_call utilizing the conf package.
+ * conf/hook_sample.py: (new file) sample for hooks
+ * conf/rule_sample.py: (new file) sample for rules
+ * REAMDE: Update sections about customizing rules and hooks.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * exc: (new package) package for miscellaneous exceptions
+ * WgetTest.py: Move TestFailed to exc/test_failed.py.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * Test-Proto.py: Fix a typo (line 71: server to servers).
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * WgetTest.py: Move WgetFile to package misc.
+ * README: Modify documentation respect to WgetFile.
+ * Test-*.py: Optimize imports about WgetFile.
+
+2014-03-13 Zihang Chen <chsc4698@gmail.com>
+
+ * misc: (new package) package for miscellaneous modules
+ * ColourTerm.py: Move to package misc and rename to colour_terminal.py,
+ add print_color functions to reduce the use of string literals like
+ "BLUE", "RED" etc.
+ * WgetTest.py:
+ (CommonMethods.Server_setup): Change invocation to printer to print_blue.
+ (CommonMethods.FilesCrawled): Change invocation to printer to print_red.
+ (HTTPTest.__init__): Change invocations to printer to print_red and
+ print_green respectively.
+
+2014-01-02 Darshit Shah <darnir@gmail.com>
+ * Makefile.am: Add new Test--https.py to list of tests and EXTRA_DIST.
+ Also replace all tabs with spaces in file for conformity.
+ * Test--https.py: New test to check if Wget works correctly with HTTPS
+ servers
+ * HTTPServer.py: Import new modules for use in HTTPS Servers
+ (HTTPSServer): New class that generates a SSL-wrapped socket for use in a
+ HTTPS Server.
+ (HTTPSd): HTTPS daemon class. Analogous to the HTTPd class
+ * WgetTest.py: Define global variables HTTP and HTTPS to reflect Server
+ types
+ (CommonMethods.exec_wget): Add the protocol information to the URL before
+ passing it to wget
+ (HTTPTest.__init__): Edit syntax. The servers variable now accepts a list of
+ servers defined by their type. E.g. HTTP, HTTPS.
+ (HTTPTest.Server_setup): Reflect change in type of variable servers.
+ However, we maintin the value of self.servers to allow most of the code to
+ remain unchanged.
+ (HTTPTest.init_HTTPS_Server): Initialize a HTTPS Server
+ * Test-Parallel-Proto.py: Edit to reflect slight change in Test Fiel Syntax.
+ * Test-Proto.py: Same
+
+2014-01-02 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (CommonMentods.exec_wget): Wait for n seconds before calling
+ the Wget executable.
+
+2013-12-27 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py: Add modeline
+ (CommonMethods.ServerConf): New pre-test hook that sets
+ BaseHTTPRequestHandler class variables in all available servers
+ * HTTPServer.py (HTTPd.ServerConf): Call the respective method in the Server
+ to set the class variables
+ (StoppableHTTPServer.server_sett): Set the handler class variables
+
+2013-12-26 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (HTTPTest.call_test): Correct the call to stop_HTTP_Server.
+
+2013-12-25 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (CommonMehtods.exec_wget): Catch and handle exception if the
+ Wget executable is not found at src/wget
+ (HTTPTest.call_test): In case of error during execution, remove all existing
+ servers before quitting
+
+2013-12-15 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (HTTPTest.HTTP_setup): Rename to Server_setup so it can be
+ easily reused for other non-HTTP servers.
+ (HTTPTest.__init__): Call Server_setup instead of HTTP_setup
+ (HTTPTest.Server_setup): Split into three more functions, that handle
+ pre-hooks, test execution and post-hooks respectively.
+ (HTTPTest.pre_hook_call): Set up and execute the pre-test hooks. Code split
+ from HTTPTest.Server_setup
+ (HTTPTest.call_test): Execute wget and log exit code. Code split from
+ HTTPTest.Server_setup
+ (HTTPTest.post_hook_call): Set up and execute post-test hooks. Code split
+ from HTTPTest.Server_setup
+
+2013-10-14 Giuseppe Scrivano <gscrivan@redhat.com>
+
+ * Makefile.am (XFAIL_TESTS): Remove Test--spider-r.py.
+
+2013-10-06 Giuseppe Scrivano <gscrivan@redhat.com>
+
+ * Makefile.am (EXTRA_DIST): Distribute test files.
+
+2013-09-16 Darshit Shah <darnir@gmail.com>
+
+ * README: Update documentation
+
+2013-09-14 Darshit Shah <darnir@gmail.com>
+
+ * HTTPServer.py (StoppableHTTPServer): Define object variable
+ request_headers which stores a list of requests received by the server
+ (StoppableHTTPServer.get_req_headers): Return the list of Request
+ Headers stored by the server
+ (_Handler.do_HEAD): Send the Request MEthod string for identification
+ (_Handler.do_GET): Same
+ (_Handler.__log_request): Log the request in Request_Headers list
+ (_Handler.send_head): Make a call to __log_request
+ * Test--spider-r.py: Add new list, Request_List, which contains all
+ the requests that Wget is expected to send. This will allow for
+ fine-grained tests on recursive downloading.
+ * WgetTest.py (CommonMethods.FilesCrawled): New Post-Test Hook, that
+ ensures that all the expected Files on the server were accessed as
+ expected.
+ (HTTPTest.stop_HTTP_server): On stopping server, asks it to respond
+ with list of all requests it received.
+
+2013-09-13 Darshit Shah <darnir@gmail.com>
+
+ * Test--spider-r.py: Test retrieval in recursive spider mode.
+ * Makefile.am: add new file
+
+2013-09-13 Darshit Shah <darnir@gmail.com>
+
+ * HTTPServer.py (_Handler.do_HEAD): If requested path is /, respond
+ with /index.html
+ (_Handler.do_HEAD): Smartly guess value of Content-Type Header from
+ file extension
+ (_Handler.guess_type): Use a preset list of extensions and
+ Content-Type strings. If the extension matches one in the list, use
+ that string, else default to "text/plain"
+
+2013-09-13 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (CommonMethods._replace_substring): New method that will
+ replace a substring delimited by {{ }} characters by the value of
+ self.<substring> variable
+ (CommonMethods.WgetCommands): Use the _replace_substring () call to
+ replace the substrings in the the command line.
+ (CommonMethods.ServerFiles): Run the _replace_substring () method on
+ the File contents too.
+
+2013-09-11 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (CommonMethods.exec_wget): Expect domain_list instead of
+ domain.
+ (CommonMethods.get_cmd_line): Same. Generate command line by
+ prepending to each file it's respective domain string
+ (CommonMethods.ServerFiles): Generate file_list and server_rules for
+ each Server and set the config details
+ (HTTPTest): New named parameter, servers which signifies number of
+ servers to spawn
+ (HTTPTest.HTTP_setup): This method now takes servers as a new
+ parameter. Instead of storing server and domain, we now store
+ server_list and domain_list. Each server must be initialized through a
+ loop.
+ (HTTPTest.stop_HTTP_server): Stop all servers in a loop.
+ * Test-Parallel-Proto.py: Prototype test file for multiple servers.
+
+2013-09-10 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (HTTPTest.stop_HTTP_server): With the threaded servers,
+ we can simply use the socketserver.shutdown() method to close the
+ server instead of sending a QUIT command
+ * HTTPServer.py (StoppabelHTTPServer.serve_forever): Delete method. No
+ need to override this method anymore.
+ (WgetHTTPRequestHandler.do_QUIT): No longer required
+ (HTTPd): Rename self.server to self.server_inst to reduce ambiguity
+ when referenced from WgetTest
+
+2013-09-08 Darshit Shah <darnir@gmail.com>
+
+ * README (File Structure): Add explanation about various variables
+ used consistently across all tests.
+
+2013-09-07 Darshit Shah <darnir@gmail.com>
+
+ * HTTPServer.py: Remove bunch of old code artefacts
+ * WgetTest.py: Same
+
+2013-09-07 Darshit Shah <darnir@gmail.com>
+
+ * HTTPServer.py (StoppableHTTPServer.server_conf): Change global
+ variable fileSys to an object variable. This is good programming
+ practice and required for parallel-wget support.
+ (StoppableHTTPServer.server_forever): Edit overridden method to remove
+ the global queue variable. No longer required under the new working
+ (WgetHTTPRequestHandler.do_QUIT): Don't push fileSys through the queue
+ (_Handler): Rename class __Handler to _Handler to match Python's
+ encapsulation rules
+ (_Handler.do_POST): fileSys is now an object variable of the server
+ (_Handler.do_PUT): Same
+ (_Handler.send_put): Same
+ (_Handler.send_head): Same
+ (HTTPd): New class that wraps around the server for Threading
+ (create_server): Make new object of HTTPd.
+ (spawn_server): Start the thread created through create_server
+ (ret_fileSys): Removed method. No longer required.
+ * WgetTest.py (HTTPTest.__init__): Don't explicitly set
+ self.act_retcode. Instead toggle tests_passed boolean to set the
+ correct return code.
+ (HTTPTest.HTTP_setup): We no longer call HTTPServer.spawn_server to
+ start a new instance of the server.
+ (HTTPTest.init_HTTP_server): We no longer call the old
+ create_server(), spawn_server() methods. Instead use the new HTTPd
+ class interface to create new instances of the server
+ (HTTPTest.stop_HTTP_server): Don't ask server to return fileSys.
+
+2013-09-07 Darshit Shah <darnir@gmail.com>
+
+ * Test-Post.py: Test basic functionality for sending HTTP POST
+ requests using the --method command
+ * Makefile.am: Add new test
+
+2013-09-06 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py (CommonMethods.__check_downloaded_files): Print a
+ unified diff in case there is a mismatch in the file contents
+
+2013-09-06 Darshit Shah <darnir@gmail.com>
+
+ * HTTPServer.py (WgetHTTPRequestHandler.test_cookies): Comment out the
+ old test_cookies code. This is no longer used and was causing problems
+ with expected cookies. The code will soon be removed anyways
+ * Test-cookie.py: Add new test for basic cookie functionality
+ * Test-cookie-401.py: Ensure cookies are saved during a 401 response
+ * Test-cookie-expires.py: Ensure that the Expires field is correctly
+ handled
+ * Test-cookies-domain-mismatch.py: Ensure that mismatched domains are
+ handled by Wget
+ * Makefile.am: Add the new tests
+
+2013-09-06 Darshit Shah <darnir@gmail.com>
+
+ * README: New section on pending work. Will keep updating this to keep
+ track of work that remains to be done on this implementation
+
+2013-09-05 Darshit Shah <darnir@gmail.com>
+
+ * Test-auth-with-content-disposition.py: Add test that ensures Content
+ Disposition works alongwith authentication
+ * Makefile.am: Add new test
+
+2013-09-04 Darshit Shah <darnir@gmail.com>
+
+ * Test-c-full.py: Test Continue options
+ * Makefile.am: Add Test-c-full.py and Test-O
+
+2013-09-02 Darshit Shah <darnir@gmail.com>
+
+ * Makefile.am: Add new Test
+ * Test-Head.py: New Test to ensure HEAD requests are handled correctly
+
+2013-08-31 Darshit Shah <darnir@gmail.com>
+
+ * README: Explain that TEST_NAME needs to be unique
+ * Test-auth-no-challenge.py: Edit non-unique TEST_NAME
+
+2013-08-31 Darshit Shah <darnir@gmail.com>
+
+ * HTTPTest.py (ServerError): Define new Exception for handling
+ internal control flow.
+ (StoppableHTTPServer.SendHeader): Simply pass. Do nothing. Adding
+ functionality here seems to crash for no apparent reason.
+ (stoppableHTTPServer.send_cust_headers): Minor optimization. No need
+ for extra variable.
+ (__Handler.Response): Handle explicit Response Code Rules
+ (__Handler.Authentication): Handle Authentication rules
+ (__Handler.handle_auth): Actual worker method for authentication
+ (__Handler.ExpectHeader): Ensure Expected Headers are received
+ (__Handler.RejectHeader): Ensure Blacklisted Headers are NOT received
+ (__Handler.send_HEAD): Dynamically call server rule functions based on
+ the self.rules list. This feature will later be added to POST/PUT, etc
+
+2013-08-31 Darshit Shah <darnir@gmail.com>
+
+ * WgetTest.py: Remove import module defaultdict.
+ (CommonMethods.get_server_rules): server_rules should be a dict, not a
+ defaultdict (list).
+ * HTTPServer.py (WgetHTTPRequestHandler.get_rule_list): If rule does
+ not exist, return None. Not an emppty list.
+ (WgetHTTPRequestHandler.test_cookies): Rule variable is not a list
+ (__Handler.send_cust_headers): Same
+ (__Handler.custom_response): Same
+ (__Handler.is_authorized): Same
+ (__Handler.expect_headers): Same
+ (__Handler.reject_headers): Same
+
+2013-08-31 Darshit Shah <darnir@gmail.com>
+
+ * README: (newfile) Simple help / instructions about using the Test
+ Environment.
+ * Makefile.am: (newfile) Makefile for the Test Environment. Uses the
+ Automake Parallel Test Harness
+ * WgetTest.py: (newfile) Base module that executes the Test.
+ * HTTPServer.py: (newfile) Contains the custom HTTP Server for the
+ Test Environment. Creates an instance of http.server in Python3.
+ * FTPServer.py: (newfile) Overrides methods from pyftpdlib for use in
+ the Test Environment. ** Work under progress **.
+ * ColourTerm.py: (newfile) A custom module to output coloured text to
+ the terminal. Known to work on POSIX shells.
+ * Test-Proto.py: (newfile) A prototype Test File. This should be
+ copied when writing a new Test Case.
+ * Test-Content-disposition-2.py: Test Content Disposition clobbering
+ * Test-Content-disposition.py: Test Content Disposition Headers
+ * Test-O.py: Test Output filename command
+ * Test-auth-basic-fail.py: Test returncode on auth failure
+ * Test-auth-basic.py: Test Basic Auth negotiation
+ * Test-auth-both.py: Test handling of Multiple auth providers. This
+ test currently fails.
+ * Test-auth-digest.py: Test Digest Auth Negotiation
+ * Test-auth-no-challenge-url.py: Ensure --auth-no-challenge is handled
+ when auth details are in-URL.
+ * Test-auth-no-challenge.py: Ensure --auth-no-challenge is honoured
+ * Test-auth-retcode.py: Ensure correct return code after 403 Forbidden
+ response.
diff --git a/testenv/Makefile.am b/testenv/Makefile.am
new file mode 100644
index 0000000..39ea76c
--- /dev/null
+++ b/testenv/Makefile.am
@@ -0,0 +1,65 @@
+# Makefile for `wget' utility
+# Copyright (C) 2013 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.
+
+
+AUTOMAKE_OPTIONS = parallel-tests
+AM_TESTS_ENVIRONMENT = export WGETRC=/dev/null; MAKE_CHECK=True; export MAKE_CHECK;\
+ export PYTHONPATH=$$PYTHONPATH:$(srcdir); export VALGRIND_TESTS="@VALGRIND_TESTS@";
+if HAVE_PYTHON3
+ TESTS = Test-auth-basic-fail.py \
+ Test-auth-basic.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-Content-disposition-2.py \
+ Test-Content-disposition.py \
+ Test-cookie-401.py \
+ Test-cookie-domain-mismatch.py \
+ Test-cookie-expires.py \
+ Test-cookie.py \
+ Test-Head.py \
+ Test--https.py \
+ Test--https-crl.py \
+ Test-O.py \
+ Test-Post.py \
+ Test-504.py \
+ Test--spider-r.py \
+ Test-redirect-crash.py
+
+ # added test cases expected to fail here and under TESTS
+ XFAIL_TESTS =
+endif
+
+EXTRA_DIST = certs conf exc misc server test README $(TESTS) $(XFAIL_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..ccd01c6
--- /dev/null
+++ b/testenv/Makefile.in
@@ -0,0 +1,1800 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 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 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 = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+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@
+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@
+XFAIL_TESTS =
+subdir = testenv
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/test-driver ChangeLog README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \
+ $(top_srcdir)/m4/absolute-header.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/clock_time.m4 \
+ $(top_srcdir)/m4/close.m4 $(top_srcdir)/m4/codeset.m4 \
+ $(top_srcdir)/m4/configmake.m4 $(top_srcdir)/m4/dirname.m4 \
+ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.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/fcntl-o.m4 \
+ $(top_srcdir)/m4/fcntl.m4 $(top_srcdir)/m4/fcntl_h.m4 \
+ $(top_srcdir)/m4/float_h.m4 $(top_srcdir)/m4/fnmatch.m4 \
+ $(top_srcdir)/m4/fseek.m4 $(top_srcdir)/m4/fseeko.m4 \
+ $(top_srcdir)/m4/fstat.m4 $(top_srcdir)/m4/ftell.m4 \
+ $(top_srcdir)/m4/ftello.m4 $(top_srcdir)/m4/futimens.m4 \
+ $(top_srcdir)/m4/getaddrinfo.m4 $(top_srcdir)/m4/getdelim.m4 \
+ $(top_srcdir)/m4/getdtablesize.m4 $(top_srcdir)/m4/getline.m4 \
+ $(top_srcdir)/m4/getopt.m4 $(top_srcdir)/m4/getpass.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/glibc21.m4 \
+ $(top_srcdir)/m4/gnulib-common.m4 \
+ $(top_srcdir)/m4/gnulib-comp.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/intlmacosx.m4 $(top_srcdir)/m4/intmax_t.m4 \
+ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/ioctl.m4 \
+ $(top_srcdir)/m4/iswblank.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/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/longlong.m4 \
+ $(top_srcdir)/m4/lseek.m4 $(top_srcdir)/m4/lstat.m4 \
+ $(top_srcdir)/m4/malloc.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/md5.m4 $(top_srcdir)/m4/memchr.m4 \
+ $(top_srcdir)/m4/memrchr.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/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.m4 $(top_srcdir)/m4/pathmax.m4 \
+ $(top_srcdir)/m4/pipe2.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/posix_spawn.m4 $(top_srcdir)/m4/printf.m4 \
+ $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/raise.m4 $(top_srcdir)/m4/rawmemchr.m4 \
+ $(top_srcdir)/m4/realloc.m4 $(top_srcdir)/m4/regex.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/sha1.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/strcase.m4 $(top_srcdir)/m4/strchrnul.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/strptime.m4 $(top_srcdir)/m4/strtok_r.m4 \
+ $(top_srcdir)/m4/strtoll.m4 $(top_srcdir)/m4/sys_ioctl_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/unistd-safer.m4 \
+ $(top_srcdir)/m4/unistd_h.m4 $(top_srcdir)/m4/unlocked-io.m4 \
+ $(top_srcdir)/m4/utimbuf.m4 $(top_srcdir)/m4/utimens.m4 \
+ $(top_srcdir)/m4/utimes.m4 $(top_srcdir)/m4/vasnprintf.m4 \
+ $(top_srcdir)/m4/vasprintf.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/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/wint_t.m4 \
+ $(top_srcdir)/m4/write.m4 $(top_srcdir)/m4/xalloc.m4 \
+ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/m4/xstrndup.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+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`
+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
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkglibexecdir = @pkglibexecdir@
+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@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+COMMENT_IF_NO_POD2MAN = @COMMENT_IF_NO_POD2MAN@
+CONFIG_INCLUDE = @CONFIG_INCLUDE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+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@
+EXEEXT = @EXEEXT@
+FLOAT_H = @FLOAT_H@
+FNMATCH_H = @FNMATCH_H@
+GETADDRINFO_LIB = @GETADDRINFO_LIB@
+GETOPT_H = @GETOPT_H@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GLIBC21 = @GLIBC21@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIB_ACCEPT = @GNULIB_ACCEPT@
+GNULIB_ACCEPT4 = @GNULIB_ACCEPT4@
+GNULIB_ATOLL = @GNULIB_ATOLL@
+GNULIB_BIND = @GNULIB_BIND@
+GNULIB_BTOWC = @GNULIB_BTOWC@
+GNULIB_CALLOC_POSIX = @GNULIB_CALLOC_POSIX@
+GNULIB_CANONICALIZE_FILE_NAME = @GNULIB_CANONICALIZE_FILE_NAME@
+GNULIB_CHDIR = @GNULIB_CHDIR@
+GNULIB_CHOWN = @GNULIB_CHOWN@
+GNULIB_CLOSE = @GNULIB_CLOSE@
+GNULIB_CONNECT = @GNULIB_CONNECT@
+GNULIB_DPRINTF = @GNULIB_DPRINTF@
+GNULIB_DUP = @GNULIB_DUP@
+GNULIB_DUP2 = @GNULIB_DUP2@
+GNULIB_DUP3 = @GNULIB_DUP3@
+GNULIB_DUPLOCALE = @GNULIB_DUPLOCALE@
+GNULIB_ENVIRON = @GNULIB_ENVIRON@
+GNULIB_EUIDACCESS = @GNULIB_EUIDACCESS@
+GNULIB_FACCESSAT = @GNULIB_FACCESSAT@
+GNULIB_FCHDIR = @GNULIB_FCHDIR@
+GNULIB_FCHMODAT = @GNULIB_FCHMODAT@
+GNULIB_FCHOWNAT = @GNULIB_FCHOWNAT@
+GNULIB_FCLOSE = @GNULIB_FCLOSE@
+GNULIB_FCNTL = @GNULIB_FCNTL@
+GNULIB_FDATASYNC = @GNULIB_FDATASYNC@
+GNULIB_FDOPEN = @GNULIB_FDOPEN@
+GNULIB_FFLUSH = @GNULIB_FFLUSH@
+GNULIB_FFS = @GNULIB_FFS@
+GNULIB_FFSL = @GNULIB_FFSL@
+GNULIB_FFSLL = @GNULIB_FFSLL@
+GNULIB_FGETC = @GNULIB_FGETC@
+GNULIB_FGETS = @GNULIB_FGETS@
+GNULIB_FOPEN = @GNULIB_FOPEN@
+GNULIB_FPRINTF = @GNULIB_FPRINTF@
+GNULIB_FPRINTF_POSIX = @GNULIB_FPRINTF_POSIX@
+GNULIB_FPURGE = @GNULIB_FPURGE@
+GNULIB_FPUTC = @GNULIB_FPUTC@
+GNULIB_FPUTS = @GNULIB_FPUTS@
+GNULIB_FREAD = @GNULIB_FREAD@
+GNULIB_FREOPEN = @GNULIB_FREOPEN@
+GNULIB_FSCANF = @GNULIB_FSCANF@
+GNULIB_FSEEK = @GNULIB_FSEEK@
+GNULIB_FSEEKO = @GNULIB_FSEEKO@
+GNULIB_FSTAT = @GNULIB_FSTAT@
+GNULIB_FSTATAT = @GNULIB_FSTATAT@
+GNULIB_FSYNC = @GNULIB_FSYNC@
+GNULIB_FTELL = @GNULIB_FTELL@
+GNULIB_FTELLO = @GNULIB_FTELLO@
+GNULIB_FTRUNCATE = @GNULIB_FTRUNCATE@
+GNULIB_FUTIMENS = @GNULIB_FUTIMENS@
+GNULIB_FWRITE = @GNULIB_FWRITE@
+GNULIB_GETADDRINFO = @GNULIB_GETADDRINFO@
+GNULIB_GETC = @GNULIB_GETC@
+GNULIB_GETCHAR = @GNULIB_GETCHAR@
+GNULIB_GETCWD = @GNULIB_GETCWD@
+GNULIB_GETDELIM = @GNULIB_GETDELIM@
+GNULIB_GETDOMAINNAME = @GNULIB_GETDOMAINNAME@
+GNULIB_GETDTABLESIZE = @GNULIB_GETDTABLESIZE@
+GNULIB_GETGROUPS = @GNULIB_GETGROUPS@
+GNULIB_GETHOSTNAME = @GNULIB_GETHOSTNAME@
+GNULIB_GETLINE = @GNULIB_GETLINE@
+GNULIB_GETLOADAVG = @GNULIB_GETLOADAVG@
+GNULIB_GETLOGIN = @GNULIB_GETLOGIN@
+GNULIB_GETLOGIN_R = @GNULIB_GETLOGIN_R@
+GNULIB_GETPAGESIZE = @GNULIB_GETPAGESIZE@
+GNULIB_GETPEERNAME = @GNULIB_GETPEERNAME@
+GNULIB_GETSOCKNAME = @GNULIB_GETSOCKNAME@
+GNULIB_GETSOCKOPT = @GNULIB_GETSOCKOPT@
+GNULIB_GETSUBOPT = @GNULIB_GETSUBOPT@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GNULIB_GETUSERSHELL = @GNULIB_GETUSERSHELL@
+GNULIB_GL_UNISTD_H_GETOPT = @GNULIB_GL_UNISTD_H_GETOPT@
+GNULIB_GRANTPT = @GNULIB_GRANTPT@
+GNULIB_GROUP_MEMBER = @GNULIB_GROUP_MEMBER@
+GNULIB_ICONV = @GNULIB_ICONV@
+GNULIB_INET_NTOP = @GNULIB_INET_NTOP@
+GNULIB_INET_PTON = @GNULIB_INET_PTON@
+GNULIB_IOCTL = @GNULIB_IOCTL@
+GNULIB_ISATTY = @GNULIB_ISATTY@
+GNULIB_ISWBLANK = @GNULIB_ISWBLANK@
+GNULIB_ISWCTYPE = @GNULIB_ISWCTYPE@
+GNULIB_LCHMOD = @GNULIB_LCHMOD@
+GNULIB_LCHOWN = @GNULIB_LCHOWN@
+GNULIB_LINK = @GNULIB_LINK@
+GNULIB_LINKAT = @GNULIB_LINKAT@
+GNULIB_LISTEN = @GNULIB_LISTEN@
+GNULIB_LOCALECONV = @GNULIB_LOCALECONV@
+GNULIB_LSEEK = @GNULIB_LSEEK@
+GNULIB_LSTAT = @GNULIB_LSTAT@
+GNULIB_MALLOC_POSIX = @GNULIB_MALLOC_POSIX@
+GNULIB_MBRLEN = @GNULIB_MBRLEN@
+GNULIB_MBRTOWC = @GNULIB_MBRTOWC@
+GNULIB_MBSCASECMP = @GNULIB_MBSCASECMP@
+GNULIB_MBSCASESTR = @GNULIB_MBSCASESTR@
+GNULIB_MBSCHR = @GNULIB_MBSCHR@
+GNULIB_MBSCSPN = @GNULIB_MBSCSPN@
+GNULIB_MBSINIT = @GNULIB_MBSINIT@
+GNULIB_MBSLEN = @GNULIB_MBSLEN@
+GNULIB_MBSNCASECMP = @GNULIB_MBSNCASECMP@
+GNULIB_MBSNLEN = @GNULIB_MBSNLEN@
+GNULIB_MBSNRTOWCS = @GNULIB_MBSNRTOWCS@
+GNULIB_MBSPBRK = @GNULIB_MBSPBRK@
+GNULIB_MBSPCASECMP = @GNULIB_MBSPCASECMP@
+GNULIB_MBSRCHR = @GNULIB_MBSRCHR@
+GNULIB_MBSRTOWCS = @GNULIB_MBSRTOWCS@
+GNULIB_MBSSEP = @GNULIB_MBSSEP@
+GNULIB_MBSSPN = @GNULIB_MBSSPN@
+GNULIB_MBSSTR = @GNULIB_MBSSTR@
+GNULIB_MBSTOK_R = @GNULIB_MBSTOK_R@
+GNULIB_MBTOWC = @GNULIB_MBTOWC@
+GNULIB_MEMCHR = @GNULIB_MEMCHR@
+GNULIB_MEMMEM = @GNULIB_MEMMEM@
+GNULIB_MEMPCPY = @GNULIB_MEMPCPY@
+GNULIB_MEMRCHR = @GNULIB_MEMRCHR@
+GNULIB_MKDIRAT = @GNULIB_MKDIRAT@
+GNULIB_MKDTEMP = @GNULIB_MKDTEMP@
+GNULIB_MKFIFO = @GNULIB_MKFIFO@
+GNULIB_MKFIFOAT = @GNULIB_MKFIFOAT@
+GNULIB_MKNOD = @GNULIB_MKNOD@
+GNULIB_MKNODAT = @GNULIB_MKNODAT@
+GNULIB_MKOSTEMP = @GNULIB_MKOSTEMP@
+GNULIB_MKOSTEMPS = @GNULIB_MKOSTEMPS@
+GNULIB_MKSTEMP = @GNULIB_MKSTEMP@
+GNULIB_MKSTEMPS = @GNULIB_MKSTEMPS@
+GNULIB_MKTIME = @GNULIB_MKTIME@
+GNULIB_NANOSLEEP = @GNULIB_NANOSLEEP@
+GNULIB_NL_LANGINFO = @GNULIB_NL_LANGINFO@
+GNULIB_NONBLOCKING = @GNULIB_NONBLOCKING@
+GNULIB_OBSTACK_PRINTF = @GNULIB_OBSTACK_PRINTF@
+GNULIB_OBSTACK_PRINTF_POSIX = @GNULIB_OBSTACK_PRINTF_POSIX@
+GNULIB_OPEN = @GNULIB_OPEN@
+GNULIB_OPENAT = @GNULIB_OPENAT@
+GNULIB_PCLOSE = @GNULIB_PCLOSE@
+GNULIB_PERROR = @GNULIB_PERROR@
+GNULIB_PIPE = @GNULIB_PIPE@
+GNULIB_PIPE2 = @GNULIB_PIPE2@
+GNULIB_POPEN = @GNULIB_POPEN@
+GNULIB_POSIX_OPENPT = @GNULIB_POSIX_OPENPT@
+GNULIB_POSIX_SPAWN = @GNULIB_POSIX_SPAWN@
+GNULIB_POSIX_SPAWNATTR_DESTROY = @GNULIB_POSIX_SPAWNATTR_DESTROY@
+GNULIB_POSIX_SPAWNATTR_GETFLAGS = @GNULIB_POSIX_SPAWNATTR_GETFLAGS@
+GNULIB_POSIX_SPAWNATTR_GETPGROUP = @GNULIB_POSIX_SPAWNATTR_GETPGROUP@
+GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM = @GNULIB_POSIX_SPAWNATTR_GETSCHEDPARAM@
+GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY = @GNULIB_POSIX_SPAWNATTR_GETSCHEDPOLICY@
+GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT = @GNULIB_POSIX_SPAWNATTR_GETSIGDEFAULT@
+GNULIB_POSIX_SPAWNATTR_GETSIGMASK = @GNULIB_POSIX_SPAWNATTR_GETSIGMASK@
+GNULIB_POSIX_SPAWNATTR_INIT = @GNULIB_POSIX_SPAWNATTR_INIT@
+GNULIB_POSIX_SPAWNATTR_SETFLAGS = @GNULIB_POSIX_SPAWNATTR_SETFLAGS@
+GNULIB_POSIX_SPAWNATTR_SETPGROUP = @GNULIB_POSIX_SPAWNATTR_SETPGROUP@
+GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM = @GNULIB_POSIX_SPAWNATTR_SETSCHEDPARAM@
+GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY = @GNULIB_POSIX_SPAWNATTR_SETSCHEDPOLICY@
+GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT = @GNULIB_POSIX_SPAWNATTR_SETSIGDEFAULT@
+GNULIB_POSIX_SPAWNATTR_SETSIGMASK = @GNULIB_POSIX_SPAWNATTR_SETSIGMASK@
+GNULIB_POSIX_SPAWNP = @GNULIB_POSIX_SPAWNP@
+GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE@
+GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2@
+GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN@
+GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_DESTROY@
+GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT = @GNULIB_POSIX_SPAWN_FILE_ACTIONS_INIT@
+GNULIB_PREAD = @GNULIB_PREAD@
+GNULIB_PRINTF = @GNULIB_PRINTF@
+GNULIB_PRINTF_POSIX = @GNULIB_PRINTF_POSIX@
+GNULIB_PSELECT = @GNULIB_PSELECT@
+GNULIB_PTHREAD_SIGMASK = @GNULIB_PTHREAD_SIGMASK@
+GNULIB_PTSNAME = @GNULIB_PTSNAME@
+GNULIB_PTSNAME_R = @GNULIB_PTSNAME_R@
+GNULIB_PUTC = @GNULIB_PUTC@
+GNULIB_PUTCHAR = @GNULIB_PUTCHAR@
+GNULIB_PUTENV = @GNULIB_PUTENV@
+GNULIB_PUTS = @GNULIB_PUTS@
+GNULIB_PWRITE = @GNULIB_PWRITE@
+GNULIB_QSORT_R = @GNULIB_QSORT_R@
+GNULIB_RAISE = @GNULIB_RAISE@
+GNULIB_RANDOM = @GNULIB_RANDOM@
+GNULIB_RANDOM_R = @GNULIB_RANDOM_R@
+GNULIB_RAWMEMCHR = @GNULIB_RAWMEMCHR@
+GNULIB_READ = @GNULIB_READ@
+GNULIB_READLINK = @GNULIB_READLINK@
+GNULIB_READLINKAT = @GNULIB_READLINKAT@
+GNULIB_REALLOC_POSIX = @GNULIB_REALLOC_POSIX@
+GNULIB_REALPATH = @GNULIB_REALPATH@
+GNULIB_RECV = @GNULIB_RECV@
+GNULIB_RECVFROM = @GNULIB_RECVFROM@
+GNULIB_REMOVE = @GNULIB_REMOVE@
+GNULIB_RENAME = @GNULIB_RENAME@
+GNULIB_RENAMEAT = @GNULIB_RENAMEAT@
+GNULIB_RMDIR = @GNULIB_RMDIR@
+GNULIB_RPMATCH = @GNULIB_RPMATCH@
+GNULIB_SCANF = @GNULIB_SCANF@
+GNULIB_SECURE_GETENV = @GNULIB_SECURE_GETENV@
+GNULIB_SELECT = @GNULIB_SELECT@
+GNULIB_SEND = @GNULIB_SEND@
+GNULIB_SENDTO = @GNULIB_SENDTO@
+GNULIB_SETENV = @GNULIB_SETENV@
+GNULIB_SETHOSTNAME = @GNULIB_SETHOSTNAME@
+GNULIB_SETLOCALE = @GNULIB_SETLOCALE@
+GNULIB_SETSOCKOPT = @GNULIB_SETSOCKOPT@
+GNULIB_SHUTDOWN = @GNULIB_SHUTDOWN@
+GNULIB_SIGACTION = @GNULIB_SIGACTION@
+GNULIB_SIGNAL_H_SIGPIPE = @GNULIB_SIGNAL_H_SIGPIPE@
+GNULIB_SIGPROCMASK = @GNULIB_SIGPROCMASK@
+GNULIB_SLEEP = @GNULIB_SLEEP@
+GNULIB_SNPRINTF = @GNULIB_SNPRINTF@
+GNULIB_SOCKET = @GNULIB_SOCKET@
+GNULIB_SPRINTF_POSIX = @GNULIB_SPRINTF_POSIX@
+GNULIB_STAT = @GNULIB_STAT@
+GNULIB_STDIO_H_NONBLOCKING = @GNULIB_STDIO_H_NONBLOCKING@
+GNULIB_STDIO_H_SIGPIPE = @GNULIB_STDIO_H_SIGPIPE@
+GNULIB_STPCPY = @GNULIB_STPCPY@
+GNULIB_STPNCPY = @GNULIB_STPNCPY@
+GNULIB_STRCASESTR = @GNULIB_STRCASESTR@
+GNULIB_STRCHRNUL = @GNULIB_STRCHRNUL@
+GNULIB_STRDUP = @GNULIB_STRDUP@
+GNULIB_STRERROR = @GNULIB_STRERROR@
+GNULIB_STRERROR_R = @GNULIB_STRERROR_R@
+GNULIB_STRNCAT = @GNULIB_STRNCAT@
+GNULIB_STRNDUP = @GNULIB_STRNDUP@
+GNULIB_STRNLEN = @GNULIB_STRNLEN@
+GNULIB_STRPBRK = @GNULIB_STRPBRK@
+GNULIB_STRPTIME = @GNULIB_STRPTIME@
+GNULIB_STRSEP = @GNULIB_STRSEP@
+GNULIB_STRSIGNAL = @GNULIB_STRSIGNAL@
+GNULIB_STRSTR = @GNULIB_STRSTR@
+GNULIB_STRTOD = @GNULIB_STRTOD@
+GNULIB_STRTOK_R = @GNULIB_STRTOK_R@
+GNULIB_STRTOLL = @GNULIB_STRTOLL@
+GNULIB_STRTOULL = @GNULIB_STRTOULL@
+GNULIB_STRVERSCMP = @GNULIB_STRVERSCMP@
+GNULIB_SYMLINK = @GNULIB_SYMLINK@
+GNULIB_SYMLINKAT = @GNULIB_SYMLINKAT@
+GNULIB_SYSTEM_POSIX = @GNULIB_SYSTEM_POSIX@
+GNULIB_TIMEGM = @GNULIB_TIMEGM@
+GNULIB_TIME_R = @GNULIB_TIME_R@
+GNULIB_TMPFILE = @GNULIB_TMPFILE@
+GNULIB_TOWCTRANS = @GNULIB_TOWCTRANS@
+GNULIB_TTYNAME_R = @GNULIB_TTYNAME_R@
+GNULIB_UNISTD_H_NONBLOCKING = @GNULIB_UNISTD_H_NONBLOCKING@
+GNULIB_UNISTD_H_SIGPIPE = @GNULIB_UNISTD_H_SIGPIPE@
+GNULIB_UNLINK = @GNULIB_UNLINK@
+GNULIB_UNLINKAT = @GNULIB_UNLINKAT@
+GNULIB_UNLOCKPT = @GNULIB_UNLOCKPT@
+GNULIB_UNSETENV = @GNULIB_UNSETENV@
+GNULIB_USLEEP = @GNULIB_USLEEP@
+GNULIB_UTIMENSAT = @GNULIB_UTIMENSAT@
+GNULIB_VASPRINTF = @GNULIB_VASPRINTF@
+GNULIB_VDPRINTF = @GNULIB_VDPRINTF@
+GNULIB_VFPRINTF = @GNULIB_VFPRINTF@
+GNULIB_VFPRINTF_POSIX = @GNULIB_VFPRINTF_POSIX@
+GNULIB_VFSCANF = @GNULIB_VFSCANF@
+GNULIB_VPRINTF = @GNULIB_VPRINTF@
+GNULIB_VPRINTF_POSIX = @GNULIB_VPRINTF_POSIX@
+GNULIB_VSCANF = @GNULIB_VSCANF@
+GNULIB_VSNPRINTF = @GNULIB_VSNPRINTF@
+GNULIB_VSPRINTF_POSIX = @GNULIB_VSPRINTF_POSIX@
+GNULIB_WAITPID = @GNULIB_WAITPID@
+GNULIB_WCPCPY = @GNULIB_WCPCPY@
+GNULIB_WCPNCPY = @GNULIB_WCPNCPY@
+GNULIB_WCRTOMB = @GNULIB_WCRTOMB@
+GNULIB_WCSCASECMP = @GNULIB_WCSCASECMP@
+GNULIB_WCSCAT = @GNULIB_WCSCAT@
+GNULIB_WCSCHR = @GNULIB_WCSCHR@
+GNULIB_WCSCMP = @GNULIB_WCSCMP@
+GNULIB_WCSCOLL = @GNULIB_WCSCOLL@
+GNULIB_WCSCPY = @GNULIB_WCSCPY@
+GNULIB_WCSCSPN = @GNULIB_WCSCSPN@
+GNULIB_WCSDUP = @GNULIB_WCSDUP@
+GNULIB_WCSLEN = @GNULIB_WCSLEN@
+GNULIB_WCSNCASECMP = @GNULIB_WCSNCASECMP@
+GNULIB_WCSNCAT = @GNULIB_WCSNCAT@
+GNULIB_WCSNCMP = @GNULIB_WCSNCMP@
+GNULIB_WCSNCPY = @GNULIB_WCSNCPY@
+GNULIB_WCSNLEN = @GNULIB_WCSNLEN@
+GNULIB_WCSNRTOMBS = @GNULIB_WCSNRTOMBS@
+GNULIB_WCSPBRK = @GNULIB_WCSPBRK@
+GNULIB_WCSRCHR = @GNULIB_WCSRCHR@
+GNULIB_WCSRTOMBS = @GNULIB_WCSRTOMBS@
+GNULIB_WCSSPN = @GNULIB_WCSSPN@
+GNULIB_WCSSTR = @GNULIB_WCSSTR@
+GNULIB_WCSTOK = @GNULIB_WCSTOK@
+GNULIB_WCSWIDTH = @GNULIB_WCSWIDTH@
+GNULIB_WCSXFRM = @GNULIB_WCSXFRM@
+GNULIB_WCTOB = @GNULIB_WCTOB@
+GNULIB_WCTOMB = @GNULIB_WCTOMB@
+GNULIB_WCTRANS = @GNULIB_WCTRANS@
+GNULIB_WCTYPE = @GNULIB_WCTYPE@
+GNULIB_WCWIDTH = @GNULIB_WCWIDTH@
+GNULIB_WMEMCHR = @GNULIB_WMEMCHR@
+GNULIB_WMEMCMP = @GNULIB_WMEMCMP@
+GNULIB_WMEMCPY = @GNULIB_WMEMCPY@
+GNULIB_WMEMMOVE = @GNULIB_WMEMMOVE@
+GNULIB_WMEMSET = @GNULIB_WMEMSET@
+GNULIB_WRITE = @GNULIB_WRITE@
+GNULIB__EXIT = @GNULIB__EXIT@
+GNUTLS_CFLAGS = @GNUTLS_CFLAGS@
+GNUTLS_LIBS = @GNUTLS_LIBS@
+GREP = @GREP@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+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_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_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_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+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_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_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP2 = @HAVE_DUP2@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+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_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFS = @HAVE_FFS@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+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_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISWBLANK = @HAVE_ISWBLANK@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+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_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LONG_LONG_INT = @HAVE_LONG_LONG_INT@
+HAVE_LSTAT = @HAVE_LSTAT@
+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_MEMCHR = @HAVE_MEMCHR@
+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_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+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_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_RAISE = @HAVE_RAISE@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SCHED_H = @HAVE_SCHED_H@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SIGACTION = @HAVE_SIGACTION@
+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_STRINGS_H = @HAVE_STRINGS_H@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+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_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_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_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_UNSIGNED_LONG_LONG_INT = @HAVE_UNSIGNED_LONG_LONG_INT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VALGRIND = @HAVE_VALGRIND@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+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_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_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@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+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@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPSL_CFLAGS = @LIBPSL_CFLAGS@
+LIBPSL_LIBS = @LIBPSL_LIBS@
+LIBPTH = @LIBPTH@
+LIBPTH_PREFIX = @LIBPTH_PREFIX@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSSL = @LIBSSL@
+LIBSSL_PREFIX = @LIBSSL_PREFIX@
+LIBTHREAD = @LIBTHREAD@
+LIBUNISTRING_UNITYPES_H = @LIBUNISTRING_UNITYPES_H@
+LIBUNISTRING_UNIWIDTH_H = @LIBUNISTRING_UNIWIDTH_H@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_CRYPTO = @LIB_CRYPTO@
+LIB_POSIX_SPAWN = @LIB_POSIX_SPAWN@
+LIB_SELECT = @LIB_SELECT@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+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@
+LTLIBPTH = @LTLIBPTH@
+LTLIBSSL = @LTLIBSSL@
+LTLIBTHREAD = @LTLIBTHREAD@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NETINET_IN_H = @NETINET_IN_H@
+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_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_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_ICONV_H = @NEXT_AS_FIRST_DIRECTIVE_ICONV_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_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_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_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_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_FLOAT_H = @NEXT_FLOAT_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_ICONV_H = @NEXT_ICONV_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_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_IOCTL_H = @NEXT_SYS_IOCTL_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_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@
+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@
+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_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC = @REPLACE_CALLOC@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+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_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_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_IOCTL = @REPLACE_IOCTL@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+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 = @REPLACE_MALLOC@
+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_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+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_PERROR = @REPLACE_PERROR@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_SPAWN = @REPLACE_POSIX_SPAWN@
+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_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_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOC = @REPLACE_REALLOC@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_SELECT = @REPLACE_SELECT@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+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_STRERROR_R = @REPLACE_STRERROR_R@
+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_STRTOK_R = @REPLACE_STRTOK_R@
+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_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+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_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WRITE = @REPLACE_WRITE@
+SCHED_H = @SCHED_H@
+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@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+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@
+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@
+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_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+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@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+lispdir = @lispdir@
+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@
+AUTOMAKE_OPTIONS = parallel-tests
+AM_TESTS_ENVIRONMENT = export WGETRC=/dev/null; MAKE_CHECK=True; export MAKE_CHECK;\
+ export PYTHONPATH=$$PYTHONPATH:$(srcdir); export VALGRIND_TESTS="@VALGRIND_TESTS@";
+
+@HAVE_PYTHON3_TRUE@TESTS = Test-auth-basic-fail.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-basic.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-both.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-digest.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-no-challenge.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-no-challenge-url.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-retcode.py \
+@HAVE_PYTHON3_TRUE@ Test-auth-with-content-disposition.py \
+@HAVE_PYTHON3_TRUE@ Test-c-full.py \
+@HAVE_PYTHON3_TRUE@ Test-Content-disposition-2.py \
+@HAVE_PYTHON3_TRUE@ Test-Content-disposition.py \
+@HAVE_PYTHON3_TRUE@ Test-cookie-401.py \
+@HAVE_PYTHON3_TRUE@ Test-cookie-domain-mismatch.py \
+@HAVE_PYTHON3_TRUE@ Test-cookie-expires.py \
+@HAVE_PYTHON3_TRUE@ Test-cookie.py \
+@HAVE_PYTHON3_TRUE@ Test-Head.py \
+@HAVE_PYTHON3_TRUE@ Test--https.py \
+@HAVE_PYTHON3_TRUE@ Test--https-crl.py \
+@HAVE_PYTHON3_TRUE@ Test-O.py \
+@HAVE_PYTHON3_TRUE@ Test-Post.py \
+@HAVE_PYTHON3_TRUE@ Test-504.py \
+@HAVE_PYTHON3_TRUE@ Test--spider-r.py \
+@HAVE_PYTHON3_TRUE@ Test-redirect-crash.py
+
+EXTRA_DIST = certs conf exc misc server test README $(TESTS) $(XFAIL_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
+.PRECIOUS: 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__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ 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; \
+ else \
+ 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 for $(PACKAGE_STRING)$${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: $(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
+
+
+@HAVE_PYTHON3_TRUE@ # added test cases expected to fail here and under TESTS
+
+# 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..081a957
--- /dev/null
+++ b/testenv/README
@@ -0,0 +1,305 @@
+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 verion 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:
+$ ./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.
+
+
+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.
+Next, is the const variable, TEST_NAME that defines the name of the Test.
+
+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 paramter, one may pass only those parameters
+that are required by the File object.
+
+The timestamp string should be a valid Unix Timestamp as defined in RFC xxxx.
+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 invokation. 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 invokation. 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.
+ * 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:
+{
+ name,
+ pre_hook,
+ test_options,
+ post_hook,
+ protocols
+}
+name should be a string, and is usually passed to the TEST_NAME variable,
+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.
+
+ * 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 invokation. 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.
+
+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.
+
+Remember to always name the Test correctly using the TEST_NAME variable. This
+is essential since a directory with the Test Name is created and this can
+cause synchronization problems when the Parallel Test Harness is used.
+One can use the following command on Unix systems to check for TEST_NAME
+clashes:
+$ grep -r -h "TEST_NAME =" | cut -c13- | uniq -c -d
+
+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 implemention
+ * 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--https-crl.py b/testenv/Test--https-crl.py
new file mode 100755
index 0000000..9330a1e
--- /dev/null
+++ b/testenv/Test--https-crl.py
@@ -0,0 +1,50 @@
+#!/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
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+TEST_NAME = "HTTPS CRL"
+############# 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 (
+ name=TEST_NAME,
+ 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..b8d4faf
--- /dev/null
+++ b/testenv/Test--https.py
@@ -0,0 +1,55 @@
+#!/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
+import os
+
+"""
+ This test ensures that Wget can download files from HTTPS Servers
+"""
+TEST_NAME = "HTTPS Downloads"
+############# 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 (
+ name=TEST_NAME,
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test,
+ protocols=Servers
+).begin ()
+
+exit (err)
diff --git a/testenv/Test--spider-r.py b/testenv/Test--spider-r.py
new file mode 100755
index 0000000..5eb01e4
--- /dev/null
+++ b/testenv/Test--spider-r.py
@@ -0,0 +1,106 @@
+#!/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.
+"""
+TEST_NAME = "Recursive Spider"
+############# File Definitions ###############################################
+mainpage = """
+<html>
+<head>
+ <title>Main Page</title>
+</head>
+<body>
+ <p>
+ Some text and a link to a <a href="http://127.0.0.1:{{port}}/secondpage.html">second page</a>.
+ Also, a <a href="http://127.0.0.1:{{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://127.0.0.1:{{port}}/thirdpage.html">third page</a>.
+ Also, a <a href="http://127.0.0.1:{{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://127.0.0.1:{{port}}/dummy.txt">text file</a>.
+ Also, another <a href="http://127.0.0.1:{{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 (
+ name=TEST_NAME,
+ 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..4d82704
--- /dev/null
+++ b/testenv/Test-504.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
+
+"""
+ 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.
+"""
+TEST_NAME = "504 Gateway Timeouts"
+############# 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 (
+ name=TEST_NAME,
+ 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..44ea77d
--- /dev/null
+++ b/testenv/Test-Content-disposition-2.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 the appropriate file when the said filename exists.
+"""
+TEST_NAME = "Content Disposition Clobber"
+############# 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 (
+ name=TEST_NAME,
+ 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..027a9e8
--- /dev/null
+++ b/testenv/Test-Content-disposition.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 parses the Content-Disposition header
+ correctly and creates a local file accordingly.
+"""
+TEST_NAME = "Content Disposition Header"
+############# 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.Tolkein"
+ }
+}
+A_File = WgetFile ("LOTR", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--content-disposition"
+WGET_URLS = [["LOTR"]]
+
+Files = [[A_File]]
+
+ExpectedReturnCode = 0
+ExpectedDownloadedFiles = [WgetFile ("JRR.Tolkein", 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 (
+ name=TEST_NAME,
+ 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..77e5c57
--- /dev/null
+++ b/testenv/Test-Head.py
@@ -0,0 +1,44 @@
+#!/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
+"""
+TEST_NAME = "HEAD Requests"
+############# 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 (
+ name=TEST_NAME,
+ 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..90cb146
--- /dev/null
+++ b/testenv/Test-O.py
@@ -0,0 +1,45 @@
+#!/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.
+"""
+TEST_NAME = "Output Filename Command"
+############# 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 (
+ name=TEST_NAME,
+ 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..223641a
--- /dev/null
+++ b/testenv/Test-Post.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
+
+"""
+ Simple test for HTTP POST Requests usiong the --method command
+"""
+TEST_NAME = "HTTP POST Requests"
+############# 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 (
+ name=TEST_NAME,
+ 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..0badf69
--- /dev/null
+++ b/testenv/Test-auth-basic-fail.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
+
+"""
+ This test ensures that Wget returns the correct exit code when Basic
+ authentcation failes due to a username/password error.
+"""
+TEST_NAME = "Basic Authentication Failure"
+############# File Definitions ###############################################
+File1 = "I am an invisble 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 (
+ name=TEST_NAME,
+ 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..49bb27b
--- /dev/null
+++ b/testenv/Test-auth-basic.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 Wget's Basic Authorization Negotiation.
+ Also, we ensure that Wget saves the host after a successfull auth and
+ doesn't wait for a challenge the second time.
+"""
+TEST_NAME = "Basic Authorization"
+############# File Definitions ###############################################
+File1 = "I am an invisble 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 (
+ name=TEST_NAME,
+ 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..91d72b8
--- /dev/null
+++ b/testenv/Test-auth-both.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 Wget's Basic Authorization Negotiation.
+ Also, we ensure that Wget saves the host after a successfull auth and
+ doesn't wait for a challenge the second time.
+"""
+TEST_NAME = "Multiple authentication support"
+############# 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"
+ },
+ "RejectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+File2_rules = {
+ "Authentication" : {
+ "Type" : "Both_inline",
+ "User" : "Sauron",
+ "Pass" : "TheEye"
+ },
+ "RejectHeader" : {
+ "Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
+ }
+}
+File3_rules = {
+ "Authentication" : {
+ "Type" : "Digest",
+ "User" : "Sauron",
+ "Pass" : "TheEye"
+ }
+}
+
+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 (
+ name=TEST_NAME,
+ 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..8a73c0d
--- /dev/null
+++ b/testenv/Test-auth-digest.py
@@ -0,0 +1,50 @@
+#!/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.
+"""
+TEST_NAME = "Digest Authorization"
+############# File Definitions ###############################################
+File1 = "Need a cookie?"
+
+File1_rules = {
+ "Authentication" : {
+ "Type" : "Digest",
+ "User" : "Pacman",
+ "Pass" : "Omnomnom"
+ }
+}
+A_File = WgetFile ("File1", File1, rules=File1_rules)
+
+WGET_OPTIONS = "--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 (
+ name=TEST_NAME,
+ 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..9e06260
--- /dev/null
+++ b/testenv/Test-auth-no-challenge-url.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 Wget's Basic Authorization Negotiation, when credentials
+ are provided in-URL
+"""
+TEST_NAME = "Auth no challenge 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 (
+ name=TEST_NAME,
+ 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..d155d72
--- /dev/null
+++ b/testenv/Test-auth-no-challenge.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 Wget's Basic Authorization Negotiation, when the
+ --auth-no-challenge command is used.
+"""
+TEST_NAME = "Auth No Challenge Command"
+############# 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 (
+ name=TEST_NAME,
+ 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..13eb583
--- /dev/null
+++ b/testenv/Test-auth-retcode.py
@@ -0,0 +1,50 @@
+#!/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.
+"""
+
+TEST_NAME = "Forbidden Retcode"
+
+############# 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 (
+ name=TEST_NAME,
+ 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..df28c91
--- /dev/null
+++ b/testenv/Test-auth-with-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 handles Content-Disposition correctly when
+ coupled with Authentication
+"""
+TEST_NAME = "Authentication with Content Disposition"
+############# 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 (
+ name=TEST_NAME,
+ 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..6dc3f5e
--- /dev/null
+++ b/testenv/Test-c-full.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
+
+"""
+ Test Wget's response when the file requested already exists on disk with
+ a filesize greater than or equal to the requested file.
+"""
+TEST_NAME = "Test continue option"
+############# 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 (
+ name=TEST_NAME,
+ 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..4ffb1ff
--- /dev/null
+++ b/testenv/Test-cookie-401.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 stores the cookie even in the event of a
+ 401 Unauthorized Response
+"""
+TEST_NAME = "Basic Cookie 401 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 (
+ name=TEST_NAME,
+ 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..05b3289
--- /dev/null
+++ b/testenv/Test-cookie-domain-mismatch.py
@@ -0,0 +1,58 @@
+#!/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.
+"""
+TEST_NAME = "Cookie Domain Mismatch"
+############# 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 (
+ name=TEST_NAME,
+ 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..0624549
--- /dev/null
+++ b/testenv/Test-cookie-expires.py
@@ -0,0 +1,81 @@
+#!/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
+"""
+TEST_NAME = "Cookie Expires"
+############# 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 (
+ name=TEST_NAME,
+ 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..1393518
--- /dev/null
+++ b/testenv/Test-cookie.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's cookie jar support works correctly.
+"""
+TEST_NAME = "Basic Cookie Functionality"
+############# 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 (
+ name=TEST_NAME,
+ pre_hook=pre_test,
+ test_params=test_options,
+ post_hook=post_test
+).begin ()
+
+exit (err)
diff --git a/testenv/Test-redirect-crash.py b/testenv/Test-redirect-crash.py
new file mode 100755
index 0000000..ac37b52
--- /dev/null
+++ b/testenv/Test-redirect-crash.py
@@ -0,0 +1,74 @@
+#!/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/"
+]
+
+TEST_NAME = "Redirection crash"
+############# 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 (
+ name=TEST_NAME,
+ 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..8d62ad6
--- /dev/null
+++ b/testenv/certs/README
@@ -0,0 +1,77 @@
+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 other certificates? (y/N): y
+Will the certificate be used to sign CRLs? (y/N): y
+Will the certificate be used to sign code? (y/N):
+Will the certificate be used to sign OCSP requests? (y/N): y
+Will the certificate be used for time stamping? (y/N):
+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):
diff --git a/testenv/certs/ca-cert.pem b/testenv/certs/ca-cert.pem
new file mode 100644
index 0000000..b516464
--- /dev/null
+++ b/testenv/certs/ca-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPjCCAiagAwIBAgIIVGI7SyiXCDUwDQYJKoZIhvcNAQELBQAwMDERMA8GA1UE
+AxMIR05VIFdnZXQxDTALBgNVBAsTBFdnZXQxDDAKBgNVBAoTA0dOVTAiGA8yMDE0
+MTExMTE2MzczM1oYDzk5OTkxMjMxMjM1OTU5WjAwMREwDwYDVQQDEwhHTlUgV2dl
+dDENMAsGA1UECxMEV2dldDEMMAoGA1UEChMDR05VMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAv2IR1/gsaJsn+egtVFbMMMbivK+eVzPY8wEXb2flpe9a
+Kkwz824nSSrWfRigQmf/ODkNlK2x91kppfPmWkClUREQB3I4d/sHFnzqCkFKmNwt
+VT4DsL47VumgZF6ZjSqTYQD3MDH3VhFj1iKrRMM/aCZXwntD+67sKw6UPXfFbfUO
+Recpb7fCZPZFVFYStxgcF7cyH+DADLX5QCEjiLYH1es6FXrdw+ypgwBl+HuLkQ/4
+gE0JLQK5PAKSYeLy0JEBUPovkMXT+r9aPkQBF/9WD6uUPia0ERHbMIT0My84hBrG
+9d5u5gXPnH1ZxKIr8iJOYCydVjYndn21zs2IExwL6wIDAQABo1gwVjAPBgNVHRMB
+Af8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMJMA8GA1UdDwEB/wQFAwMHBgAw
+HQYDVR0OBBYEFPM+TjiESqm+wW/HYaNQ2m4pi+tUMA0GCSqGSIb3DQEBCwUAA4IB
+AQCWKV1Txo3xytRSO1PwWK9ce5FhvQW9mubuuWmbEnQt9JaOhO1Og6ZmdPDlAQeo
+m0CJZZ0VNeodoBXPGopy3VyzF4ZzUR9leGk3sb1qTSoDCvJd/zLrfukHKugtwuK0
+b1fPnEjBjQ6gQI21coc1tmyX8Qsm7of5n+Ji601WG+FiVmmdEsCjmA/eAvwSbu1E
+cAVH476KUt4CrpVPQQVqzFPDz8i4iw/P+Jo+iNmL5S72OG2GfkSJq3XkUYa509W6
+N+8c3p4y0q/PcQ92s1OIHyEPZFRFhm4xw0sHkhD2KVoHseHZjCoYn4/lIzMPnJ6v
+EfZUJQXndeJnffbthaUp8Ea2
+-----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/server-cert.pem b/testenv/certs/server-cert.pem
new file mode 100644
index 0000000..4ce3886
--- /dev/null
+++ b/testenv/certs/server-cert.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDgDCCAmigAwIBAgIIVGI73zrIeeMwDQYJKoZIhvcNAQELBQAwMDERMA8GA1UE
+AxMIR05VIFdnZXQxDTALBgNVBAsTBFdnZXQxDDAKBgNVBAoTA0dOVTAiGA8yMDE0
+MTExMTE2NDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAxMRIwEAYDVQQDEwkxMjcuMC4w
+LjExDTALBgNVBAsTBFdnZXQxDDAKBgNVBAoTA0dOVTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMjC3Gt55EfStl6mE371+pD3/cpR5MLxkdbBss5MlIP2
+TDhiPOItLXml8oxs4BjUm3wfn3GV9iJLmbzbIWL+0kbRkQ2LCPKUf+Cln3z2ZE+r
+XwdWlT8gVfv51Opfkp2lLDVUqLfNKRGQgivjSCmLqY2LqeB0SaVNvuaD3EpqZyIH
+0E5SZgjqBHgRRtvGkcy0rOmp5SI2NASLugUioXa9OLWjpYDwodsd3ERlL0DJ1aJW
+8TC8Tqix4i0osWzar+LXBIin0Qvar9/uRHN0p1kq3p0XgNHKqWpiTT54+WYx7Pem
+v4qRXz11swiJzUL+Pw1DurQ9smbzDgAsz7V2FJnUeCcCAwEAAaOBmDCBlTAMBgNV
+HRMBAf8EAjAAMB8GA1UdEQQYMBaCCTEyNy4wLjAuMYIJbG9jYWxob3N0MBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFJfm323L
+JbKTM/tMKSt0qlUqewbnMB8GA1UdIwQYMBaAFPM+TjiESqm+wW/HYaNQ2m4pi+tU
+MA0GCSqGSIb3DQEBCwUAA4IBAQCDmuSD4IGmn0UQ5jhGQquh92Iu59j64Rrg7EIM
+zoppciyYR8gDUutOI9CEisxJz6umvAdOo5L981gcFaBv6hHWaE/krAZccR+ZXZP6
+fI9btO8My8O63fYcd2KkLEFqvKDF43i01S2LrqXdPo3uELbFZwxCmUKsexFGsoW1
+CbXbRjnS7w/f72myRmvBeDiNMuGfe1lb4IflybH3DMlKC7i0AN1JKglp+IKn5XAE
+neWR03i3UaYJsibIxj0DkTS+hVPu5MXQ9RlF5CkRdFKjGinLE/u70XyAyx0/IeAN
+e7c2MJvpdfRmTXm2ew4sNyK9RXo7Bv0Yqkl65iMscF8LNnxL
+-----END CERTIFICATE-----
diff --git a/testenv/certs/server-crl.pem b/testenv/certs/server-crl.pem
new file mode 100644
index 0000000..39c1919
--- /dev/null
+++ b/testenv/certs/server-crl.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB1DCBvQIBATANBgkqhkiG9w0BAQsFADAwMREwDwYDVQQDEwhHTlUgV2dldDEN
+MAsGA1UECxMEV2dldDEMMAoGA1UEChMDR05VGA8yMDE0MTExMTE2NDU1NFoYDzk5
+OTkxMjMxMjM1OTU5WjAdMBsCCFRiO986yHnjGA8yMDE0MTExMTE2NDU1NFqgNjA0
+MB8GA1UdIwQYMBaAFPM+TjiESqm+wW/HYaNQ2m4pi+tUMBEGA1UdFAQKAghUYj1E
+KHs9ijANBgkqhkiG9w0BAQsFAAOCAQEAZgwqs1VOFG39dFHHMXvBr4eJfhwiG4bC
+cL6IvLhvl9ikcyQMHrpOBtNjkCtgclSbJjjTDdera1+zuCWE0WBOJ4mojYdAIOhR
+QvSwp4NwAtibu2F/fjeXoo+LEpcRKtLvAotB30eCZ1OPrijsa/HxFILOLlayjns8
+wM4RmQC4o43y1G/1jqM8hGDg4Wz0j1URVuyP+pU55JpubV5LlExy3gIRwevD2lam
+q3hiighenJYFO3HGZkYT2SIoSpXZnQqKPJ4HwRBSg/cjOpc1y1lIIvKhmk+Cut6M
++S5HL4pIk8vGYg57nTfOOkj1goqFkfU0DBqvVAZj02ay/VIDu61T1g==
+-----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/conf/__init__.py b/testenv/conf/__init__.py
new file mode 100644
index 0000000..4b5ddc4
--- /dev/null
+++ b/testenv/conf/__init__.py
@@ -0,0 +1,47 @@
+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/__pycache__/__init__.cpython-33.pyo b/testenv/conf/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..9529d50
--- /dev/null
+++ b/testenv/conf/__pycache__/__init__.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/authentication.cpython-33.pyo b/testenv/conf/__pycache__/authentication.cpython-33.pyo
new file mode 100644
index 0000000..bf7cbbc
--- /dev/null
+++ b/testenv/conf/__pycache__/authentication.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/expect_header.cpython-33.pyo b/testenv/conf/__pycache__/expect_header.cpython-33.pyo
new file mode 100644
index 0000000..7a17355
--- /dev/null
+++ b/testenv/conf/__pycache__/expect_header.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/expected_files.cpython-33.pyo b/testenv/conf/__pycache__/expected_files.cpython-33.pyo
new file mode 100644
index 0000000..182491b
--- /dev/null
+++ b/testenv/conf/__pycache__/expected_files.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/expected_ret_code.cpython-33.pyo b/testenv/conf/__pycache__/expected_ret_code.cpython-33.pyo
new file mode 100644
index 0000000..a02a95b
--- /dev/null
+++ b/testenv/conf/__pycache__/expected_ret_code.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/files_crawled.cpython-33.pyo b/testenv/conf/__pycache__/files_crawled.cpython-33.pyo
new file mode 100644
index 0000000..7197bda
--- /dev/null
+++ b/testenv/conf/__pycache__/files_crawled.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/hook_sample.cpython-33.pyo b/testenv/conf/__pycache__/hook_sample.cpython-33.pyo
new file mode 100644
index 0000000..d71d665
--- /dev/null
+++ b/testenv/conf/__pycache__/hook_sample.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/local_files.cpython-33.pyo b/testenv/conf/__pycache__/local_files.cpython-33.pyo
new file mode 100644
index 0000000..c36044d
--- /dev/null
+++ b/testenv/conf/__pycache__/local_files.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/reject_header.cpython-33.pyo b/testenv/conf/__pycache__/reject_header.cpython-33.pyo
new file mode 100644
index 0000000..4ccf535
--- /dev/null
+++ b/testenv/conf/__pycache__/reject_header.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/response.cpython-33.pyo b/testenv/conf/__pycache__/response.cpython-33.pyo
new file mode 100644
index 0000000..08091a1
--- /dev/null
+++ b/testenv/conf/__pycache__/response.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/rule_sample.cpython-33.pyo b/testenv/conf/__pycache__/rule_sample.cpython-33.pyo
new file mode 100644
index 0000000..36f1d61
--- /dev/null
+++ b/testenv/conf/__pycache__/rule_sample.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/send_header.cpython-33.pyo b/testenv/conf/__pycache__/send_header.cpython-33.pyo
new file mode 100644
index 0000000..17ae67c
--- /dev/null
+++ b/testenv/conf/__pycache__/send_header.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/server_files.cpython-33.pyo b/testenv/conf/__pycache__/server_files.cpython-33.pyo
new file mode 100644
index 0000000..1d9f82d
--- /dev/null
+++ b/testenv/conf/__pycache__/server_files.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/urls.cpython-33.pyo b/testenv/conf/__pycache__/urls.cpython-33.pyo
new file mode 100644
index 0000000..32f558c
--- /dev/null
+++ b/testenv/conf/__pycache__/urls.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/__pycache__/wget_commands.cpython-33.pyo b/testenv/conf/__pycache__/wget_commands.cpython-33.pyo
new file mode 100644
index 0000000..4a6831c
--- /dev/null
+++ b/testenv/conf/__pycache__/wget_commands.cpython-33.pyo
Binary files differ
diff --git a/testenv/conf/authentication.py b/testenv/conf/authentication.py
new file mode 100644
index 0000000..c87994a
--- /dev/null
+++ b/testenv/conf/authentication.py
@@ -0,0 +1,22 @@
+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']
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..2c8d632
--- /dev/null
+++ b/testenv/conf/expected_files.py
@@ -0,0 +1,51 @@
+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:
+ 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)
+ if file.content != local_file['content']:
+ for line in unified_diff(local_file['content'],
+ file.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..334e596
--- /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..6230a70
--- /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..5f9c8fa
--- /dev/null
+++ b/testenv/conf/local_files.py
@@ -0,0 +1,18 @@
+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)
diff --git a/testenv/conf/reject_header.py b/testenv/conf/reject_header.py
new file mode 100644
index 0000000..53e237d
--- /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..1e9d346
--- /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 metadat 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):
+ rules = {f.name: test_obj.get_server_rules(f)
+ for f in files}
+ files = {f.name: test_obj._replace_substring(f.content)
+ for f in files}
+ server.server_conf(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..2b7522e
--- /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 invokation. 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/__pycache__/__init__.cpython-33.pyo b/testenv/exc/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..ddd2eb9
--- /dev/null
+++ b/testenv/exc/__pycache__/__init__.cpython-33.pyo
Binary files differ
diff --git a/testenv/exc/__pycache__/server_error.cpython-33.pyo b/testenv/exc/__pycache__/server_error.cpython-33.pyo
new file mode 100644
index 0000000..fd7ba4c
--- /dev/null
+++ b/testenv/exc/__pycache__/server_error.cpython-33.pyo
Binary files differ
diff --git a/testenv/exc/__pycache__/test_failed.cpython-33.pyo b/testenv/exc/__pycache__/test_failed.cpython-33.pyo
new file mode 100644
index 0000000..d87aea5
--- /dev/null
+++ b/testenv/exc/__pycache__/test_failed.cpython-33.pyo
Binary files differ
diff --git a/testenv/exc/server_error.py b/testenv/exc/server_error.py
new file mode 100644
index 0000000..b8a37ce
--- /dev/null
+++ b/testenv/exc/server_error.py
@@ -0,0 +1,7 @@
+
+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
diff --git a/testenv/exc/test_failed.py b/testenv/exc/test_failed.py
new file mode 100644
index 0000000..de5e02a
--- /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/__pycache__/__init__.cpython-33.pyo b/testenv/misc/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..0bb6da3
--- /dev/null
+++ b/testenv/misc/__pycache__/__init__.cpython-33.pyo
Binary files differ
diff --git a/testenv/misc/__pycache__/colour_terminal.cpython-33.pyo b/testenv/misc/__pycache__/colour_terminal.cpython-33.pyo
new file mode 100644
index 0000000..43caa7b
--- /dev/null
+++ b/testenv/misc/__pycache__/colour_terminal.cpython-33.pyo
Binary files differ
diff --git a/testenv/misc/__pycache__/wget_file.cpython-33.pyo b/testenv/misc/__pycache__/wget_file.cpython-33.pyo
new file mode 100644
index 0000000..7ed99db
--- /dev/null
+++ b/testenv/misc/__pycache__/wget_file.cpython-33.pyo
Binary files differ
diff --git a/testenv/misc/colour_terminal.py b/testenv/misc/colour_terminal.py
new file mode 100644
index 0000000..b0849c1
--- /dev/null
+++ b/testenv/misc/colour_terminal.py
@@ -0,0 +1,44 @@
+from functools import partial
+import platform
+from os import getenv
+
+""" 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() == 'Linux' else False
+check = False if getenv("MAKE_CHECK") == 'True' else True
+
+def printer (color, string):
+ if 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/wget_file.py b/testenv/misc/wget_file.py
new file mode 100644
index 0000000..027dced
--- /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/__pycache__/__init__.cpython-33.pyo b/testenv/server/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..7464383
--- /dev/null
+++ b/testenv/server/__pycache__/__init__.cpython-33.pyo
Binary files differ
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/__pycache__/__init__.cpython-33.pyo b/testenv/server/http/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..ec8a9e6
--- /dev/null
+++ b/testenv/server/http/__pycache__/__init__.cpython-33.pyo
Binary files differ
diff --git a/testenv/server/http/__pycache__/http_server.cpython-33.pyo b/testenv/server/http/__pycache__/http_server.cpython-33.pyo
new file mode 100644
index 0000000..b8c7ce2
--- /dev/null
+++ b/testenv/server/http/__pycache__/http_server.cpython-33.pyo
Binary files differ
diff --git a/testenv/server/http/http_server.py b/testenv/server/http/http_server.py
new file mode 100644
index 0000000..9128b3e
--- /dev/null
+++ b/testenv/server/http/http_server.py
@@ -0,0 +1,442 @@
+from http.server import HTTPServer, BaseHTTPRequestHandler
+from exc.server_error import ServerError
+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'))
+ fop = open (CERTFILE)
+ print (fop.readline())
+ self.socket = ssl.wrap_socket (
+ sock = socket.socket (self.address_family, self.socket_type),
+ ssl_version = ssl.PROTOCOL_TLSv1,
+ 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 auxilliary methods created to help in processing certain
+ requests. """
+
+ def get_rule_list (self, name):
+ return self.rules.get(name)
+
+ # The defailt 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 recieves 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.send_header ("Content-type", "text/plain")
+ content = self.server.fileSys.pop (path) + "\n" + body_data
+ total_length = len (content)
+ self.server.fileSys[path] = content
+ self.send_header ("Content-Length", total_length)
+ self.send_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.send_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.send_header (header, header_obj.headers[header])
+
+ def finish_headers (self):
+ self.send_cust_headers ()
+ self.end_headers ()
+
+ def Response (self, resp_obj):
+ self.send_response (resp_obj.response_code)
+ self.finish_headers ()
+ 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 base64 (self, data):
+ string = b64encode (data.encode ('utf-8'))
+ return string.decode ('utf-8')
+
+ def send_challenge (self, auth_type):
+ auth_type = auth_type.lower()
+ if auth_type == "both":
+ self.send_challenge ("basic")
+ self.send_challenge ("digest")
+ 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)
+ challenge_str += ', qop="auth"'
+ 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)
+ pass_auth = True
+ if self.user != params['username'] or \
+ self.nonce != params['nonce'] or \
+ self.opaque != params['opaque']:
+ pass_auth = False
+ req_attribs = ['username', 'realm', 'nonce', 'uri', 'response']
+ for attrib in req_attribs:
+ if attrib not in params:
+ pass_auth = False
+ if not self.check_response (params):
+ pass_auth = False
+ return pass_auth
+
+ 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 ServerError as se:
+ self.send_response (401, "Authorization Required")
+ self.send_challenge (auth_rule.auth_type)
+ self.finish_headers ()
+ raise ServerError (se.__str__())
+
+ 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":
+ auth_type = auth_header.split(' ')[0].lower() if auth_header else 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 ServerError ("Authentication Mechanism " + auth_type + " not supported")
+ except AttributeError as ae:
+ raise ServerError (ae.__str__())
+ if is_auth is False:
+ raise ServerError ("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 " + header_line + " not found")
+ self.finish_headers ()
+ 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 is not None and header_recd == rej_headers[header_line]:
+ self.send_error (400, 'Blacklisted Header ' + header_line + ' received')
+ self.finish_headers ()
+ 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 overriden 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)
+
+ 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 = "Method " + rule_name + " not defined"
+ self.send_error (500, msg)
+ return (None, None)
+ except ServerError as se:
+ print (se.__str__())
+ return (None, None)
+
+ content = self.server.fileSys.get (path)
+ content_length = len (content)
+ 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":
+ self.send_response (416)
+ self.finish_headers ()
+ return (None, None)
+ else:
+ self.range_begin = None
+ if self.range_begin is None:
+ self.send_response (200)
+ else:
+ self.send_response (206)
+ self.send_header ("Accept-Ranges", "bytes")
+ self.send_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.send_header ("Content-type", cont_type)
+ self.send_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=80 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/__pycache__/__init__.cpython-33.pyo b/testenv/test/__pycache__/__init__.cpython-33.pyo
new file mode 100644
index 0000000..ed9519e
--- /dev/null
+++ b/testenv/test/__pycache__/__init__.cpython-33.pyo
Binary files differ
diff --git a/testenv/test/__pycache__/base_test.cpython-33.pyo b/testenv/test/__pycache__/base_test.cpython-33.pyo
new file mode 100644
index 0000000..b60e973
--- /dev/null
+++ b/testenv/test/__pycache__/base_test.cpython-33.pyo
Binary files differ
diff --git a/testenv/test/__pycache__/http_test.cpython-33.pyo b/testenv/test/__pycache__/http_test.cpython-33.pyo
new file mode 100644
index 0000000..75681a5
--- /dev/null
+++ b/testenv/test/__pycache__/http_test.cpython-33.pyo
Binary files differ
diff --git a/testenv/test/base_test.py b/testenv/test/base_test.py
new file mode 100644
index 0000000..0d98078
--- /dev/null
+++ b/testenv/test/base_test.py
@@ -0,0 +1,233 @@
+import os
+import shutil
+import shlex
+import traceback
+import re
+import time
+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"
+
+
+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, name, pre_hook, test_params, post_hook, protocols):
+ """
+ Define the class-wide variables (or attributes).
+ Attributes should not be defined outside __init__.
+ """
+ self.name = name
+ self.pre_configs = pre_hook or {} # if pre_hook == None, then
+ # {} (an empty dict object) is
+ # passed to self.pre_configs
+ self.test_params = test_params or {}
+ self.post_configs = post_hook or {}
+ self.protocols = protocols
+
+ self.servers = []
+ self.domains = []
+ self.port = -1
+
+ self.wget_options = ''
+ self.urls = []
+
+ self.tests_passed = True
+ 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?
+ self.port = str(addr[1])
+
+ return '%s:%s' % (addr[0], 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(domain)
+
+ def exec_wget(self):
+ cmd_line = self.gen_cmd_line()
+ params = shlex.split(cmd_line)
+ print(params)
+
+ if os.getenv("SERVER_WAIT"):
+ time.sleep(float(os.getenv("SERVER_WAIT")))
+
+ try:
+ ret_code = call(params)
+ 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(".")
+ 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", "")
+ if valgrind in ("", "0"):
+ cmd_line = '%s %s ' % (wget_path, wget_options)
+ elif valgrind == "1":
+ cmd_line = 'valgrind --error-exitcode=301 --leak-check=yes --track-origins=yes %s %s ' % (wget_path, wget_options)
+ else:
+ cmd_line = '%s %s %s ' % (os.getenv("VALGRIND_TESTS", ""), wget_path, wget_options)
+
+ for protocol, urls, domain in zip(self.protocols,
+ self.urls,
+ self.domains):
+ # 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 ' % (protocol.lower(), domain, 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.")
+
+ 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):
+ pattern = re.compile ('\{\{\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 True
diff --git a/testenv/test/http_test.py b/testenv/test/http_test.py
new file mode 100644
index 0000000..230eff8
--- /dev/null
+++ b/testenv/test/http_test.py
@@ -0,0 +1,46 @@
+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,
+ name="Unnamed Test",
+ pre_hook=None,
+ test_params=None,
+ post_hook=None,
+ protocols=(HTTP,)):
+ super(HTTPTest, self).__init__(name,
+ pre_hook,
+ test_params,
+ post_hook,
+ protocols)
+ with self:
+ # if any exception occurs, self.__exit__ will be immediately called
+ self.server_setup()
+ self.do_test()
+ print_green('Test Passed.')
+
+ 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 :