173 Commits

Author SHA1 Message Date
Giuseppe Scrivano
f65f522f58 Tag release 1.17.1
* NEWS: Update.
* gnulib: sync from upstream.
2015-12-11 18:35:04 +01:00
Tim Rühsen
be84711ea4 Remove ABOUT-NLS from git
* ABOUT-NLS: Remove from repository, it will be autogenerated.
* .gitignore: Add ABOUT-NLS and build-aux/ar-lib
2015-12-11 12:11:55 +01:00
Jernej Simončič
bf56bf4560 * src/metalink.c: Specify 'rb' as mode to open file 2015-12-11 09:58:30 +01:00
Ángel González
3eddf5c173 * doc/wget.texi: add hint for self-signed certificates 2015-12-10 23:26:14 +01:00
Ander Juaristi
160f0e908f Fix Coverity issues
* src/ftp.c (getftp): on error, close the file and attempt to remove it
   before exiting.
 * src/hsts.c (hsts_store_open): update modification time in the end.
2015-12-10 23:21:27 +01:00
Darshit Shah
30b0705fa6 Faster Travis Builds
* contrib/travis-ci: Test under different languages only when all the
features are enabled. This covers the maximum number of strings. For the
other option permutations, test only in the default C locale
2015-12-10 22:43:31 +01:00
Darshit Shah
9933da2b9f Fix remaining bugs in progress bar implementation
* src/progress.c (create_image): Ensure that the entire screen width is
drawn everytime to prevent any artefacts from leaking through.
2015-12-10 13:43:45 +01:00
Darshit Shah
df7cb9a1b9 Add bug-wget to list of travis recipients
* .travis.yml: Add bug-wget to list of Travis Report Recipients
2015-12-09 09:28:58 +01:00
Darshit Shah
636a5f9a1c Eliminate more compiler warnings
* src/options.h (CHECK_CERT_MODES): Remove C99 style comma after last
value
* src/progress.c (create_image): Do not mix statements and declarations
* src/init.c (cmd_boolean_internal): Mark unused parameters
2015-12-09 09:26:24 +01:00
Darshit Shah
44937634a3 Re-enable test on multibyte locale in Travis
* .travis.yml: Use Russian locale instead of Japanese since it seems to
be more complete
* contrib/travis-ci: Re-enable testing on a Russian locale
2015-12-09 09:26:24 +01:00
Darshit Shah
2257d3ebf8 Fix progress bar assertion with multibyte locales
* src/progress.c (bar_create): Define size of progress buffer explicitly
  (create_image): Clean up progress bar image creation. Use memset
  instead of for loops to create arrays of the same byte.
2015-12-09 09:26:24 +01:00
Darshit Shah
b0d2fa5748 Introduce Travis Integration
* .travis.yml: Configuration file for Travis-CI
* contrib/travis-ci: Script to run on travis. Similar to check-hard but modified
  for travis.
* tests/valgrind-suppressions{-ssl}: Add extra suppressions to prevent a
Valgrind False Positive errors in an old version

Since Travis currently supports only public repositories on GitHub, the support
for automated testing through Travis will be done using my Clone of Wget on
GitHub at: https://github.com/darnir/wget.git
Any commits pushed to this repository will trigger a build on Travis.
2015-12-06 21:50:58 +01:00
Tim Rühsen
ca0c272eae SKIP SSL/TLS tests if configured without it
* testenv/Makefile.am: Set SSL_TESTS env variable
* testenv/Test--https-crl.py, testenv/Test--https.py,
  testenv/Test-hsts.py: Return 77 (SKIP) if SSL/TLS is not configured
2015-12-04 15:49:18 +01:00
Tim Rühsen
8977e63239 Add Test-hsts.py to SSL_TESTS
* testenv/Makefile.am: Add Test-hsts.py to SSL_TESTS
2015-12-03 16:14:24 +01:00
Ygal Blum
ad5a283528 Fix compilation when without-ssl is selected 2015-12-03 16:12:35 +01:00
Darshit Shah
3dd2e78256 Include Metalink and GPG information in version
* src/build_info.c.in: Include the presence of Metalink and GPGME features in
the output for wget --version
2015-12-03 16:02:51 +01:00
Giuseppe Scrivano
81061571d1 Add --check-certificate=quiet
* doc/wget.texi: Add documentation for  --check-certificate=quiet.
* src/options.h (enum CHECK_CERT_MODES): New enum.
* src/init.c (cmd_check_cert): New static function.
(cmd_boolean_internal): Likewise.
* src/gnutls.c (ssl_check_certificate): Handle CHECK_CERT_QUIET.
* src/openssl.c (ssl_check_certificate): Handle CHECK_CERT_QUIET.
2015-12-03 11:49:55 +01:00
Tim Rühsen
4e37fb6191 Fix regression in HTTP authentication
* src/http.c (initialize_request): Fix wrong params to search_netrc()

Regression introduced in commit 29850e77
Reported-by: Axel Reinhold <axel@freakout.de>
2015-11-24 10:39:39 +01:00
Tim Rühsen
218d81f6e5 Fix SIGSEGV in -N / --content-disposition combination
* src/http.c (http_loop): Fix SIGSEGV

Reported-by: "Schleusener, Jens" <Jens.Schleusener@t-online.de>
2015-11-23 15:10:00 +01:00
Ander Juaristi
46cd721c0f Fix potential NULL pointer dereference
* src/gnutls.c (ssl_connect_wget): check for NULL before calls
2015-11-20 19:22:25 +01:00
Giuseppe Scrivano
b1c7777037 * configure.ac: change gettext version to 0.18.1 2015-11-20 11:58:42 +01:00
Ikey Doherty
8c12260d4b configure.ac: Use correct gettext version
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2015-11-19 23:14:07 +01:00
Tim Rühsen
99aa7b4f5e Fix HSTS memory issue + test code issue
* src/hsts.c (hsts_find_entry): Fix freeing memory
  (hsts_remove_entry): Remove freeing host member
  (hsts_match): Free host member here
  (hsts_store_entry): Free host member here
  (test_url_rewrite): Fix 'created' value
  (test_hsts_read_database): Fix 'created' value

Reported-by: Dagobert Michelsen <dam@opencsw.org>
2015-11-19 12:20:35 +01:00
Tim Rühsen
76da642aaf Include errno.h instead of sys/errno.h (Solaris issue)
* src/metalink.c: Include errno.h instead of sys/errno.h

Reported-by: Dagobert Michelsen <dam@opencsw.org>
2015-11-17 14:42:25 +01:00
Darshit Shah
2cfcadf5e6 Fix compile error when IPv6 is disabled
* src/ftp-basic.c: The code for the new FTPS functionality was unintentionally
inside a #ifdef IPV6 block. Move the code around so that it is defined even when
IPV6 isn't used
2015-11-17 13:40:44 +01:00
Darshit Shah
08ece891b5 Use gnulib module flock to provide function
* bootstrap.conf: Use module flock from gnulib to provide it on other platforms
such as Windows.
2015-11-17 00:36:06 +01:00
Darshit Shah
4ed540ddc7 Eliminate NDEBUG redefined warnings
* src/wget.h: Define NDEBUG only if it hasn't been defined before
2015-11-16 23:53:59 +01:00
Giuseppe Scrivano
d1a329536a NEWS: prepare new release cycle 2015-11-15 15:23:38 +01:00
Giuseppe Scrivano
2b418d1146 Prepare release 1.17
* gnulib: sync with upstream.
* NEWS: Update.
* src/main.c: Change the copyright year.
2015-11-15 15:00:55 +01:00
Tim Rühsen
b041658451 Document combination of -nc and -O
Fixes #46359
2015-11-03 15:13:28 +01:00
Tim Rühsen
6cdfc9c143 Do not download/save file on error when --spider enabled
* src/http.c (gethttp,http_loop):
  Do not download/save file on error when --spider is enabled and not
  working recursive.

Reported-by: Сковорода Никита Андреевич chalkerx@gmail.com
Fixes #45821
2015-11-03 14:29:36 +01:00
Tim Rühsen
b14eeb5aee Fix URL conversion for colons in filenames
* src/convert.c (construct_relative): Prepend './' to filename
* tests/Test-k.px: Amend test to succeed
2015-10-27 13:13:54 +01:00
Tim Rühsen
71979f1643 Adjust indentation of --no-use-server-timestamps in help output
* src/main.c: Adjust indentation of --no-use-server-timestamps
2015-10-15 21:09:59 +02:00
Ander Juaristi
4ad201a7e7 Added --convert-file-only option
* src/convert.c (convert_links_in_hashtable, convert_links):
   test for CO_CONVERT_BASENAME_ONLY.
   (convert_basename): new function.
 * src/convert.h: new constant CO_CONVERT_BASENAME_ONLY.
 * src/init.c, src/main.c, src/options.h: new option "--convert-file-only".
 * doc/wget.texi: updated documentation.

 Reviewed-by: Gabriel Somlo <somlo@cmu.edu>
2015-10-13 16:17:20 +02:00
Darshit Shah
3608c3001c Fix Test-ftp-pasv-not-supported.px
* tests/Test-ftp-pasv-not-supported.px: We do *NOT* expect any
    downloaded files. Also, do not negate the Test response.

    The test originally expected a downloaded file, but this is not
    true. As a result, the test would fail and return exit code 1. This
    was presumably the reason why the test result was negated before
    returning to the shell. Fix this issue, so that the test runs
    correctly without any hacks.
2015-10-12 22:05:49 +05:30
Darshit Shah
d484b14174 Fix make distcheck failures in Perl SSL Tests
* tests/Makefile.am: Add valgrind-suppressions-ssl to EXTRA_DIST
    * tests/Test-proxied-https-auth-keepalive.px: Find valgrind in
    correct path during make distcheck
    * tests/Test-proxied-https-auth.px: Same
2015-10-12 22:05:44 +05:30
christian fafard
b8ee370571 Skip HTTPS perl tests if IO::Socket::SSL not installed
* tests/Test-proxied-https-auth-keepalive.px: Skip test if perl module
  IO::Socket::SSL is not installed (trivial change).
* tests/Test-proxied-https-auth.px: Skip test if perl module
  IO::Socket::SSL is not installed (trivial change).
2015-10-12 10:03:30 +02:00
Ander Juaristi
f5a63e3100 Fix potential race condition
* src/hsts.c (hsts_read_database): get an open file handle
   instead of a file name.
   (hsts_store_dump): get an open file handle
   instead of a file name.
   (hsts_store_open): open the file and pass the open file handle.
   (hsts_store_save): lock the file before the read-merge-dump
   process.

 Reported-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2015-10-09 10:13:51 +02:00
Ander Juaristi
077e897819 Fix HSTS merge bug
* src/hsts.c (hsts_store_merge): call hsts_new_entry() if the entry
   does not exist in the database.

When merging the existing HSTS database on disk with the one on memory,
the entries that were on disk but not on memory were ignored. Thus,
only the existing entries were merged. This behavior was only triggered
when more than one Wget processes were using the same HSTS database
simultaneously. This commit fixes the bug by adding the new entries
to the on-memory database if they were not found there.
2015-10-09 10:13:23 +02:00
Giuseppe Scrivano
1e7ccfe275 testenv/Test--rejected-log.py: Remove trailing white spaces 2015-09-28 16:31:11 +02:00
Tim Rühsen
26fadc55c2 Handle TLS rehandshakes in GnuTLS code
* src/gnutls.c: New static function _do_handshake()
* src/gnutls.c (wgnutls_read_timeout): Handle rehandshake
* src/gnutls.c (wgnutls_write): Handle rehandshake
* src/gnutls.c (ssl_connect_wget): Move handshake code into _do_handshake()

Fixes #46061
2015-09-28 16:18:33 +02:00
Darshit Shah
e51076e683 Add tests for missing qop in digest auth
* testenv/test-auth-both.py: Add qop parameter for digest auth
    * testenv/test-auth-digest.py: Same
    * testenv/conf/authentication.py: Support additional parameters for
    authentication
    * testenv/servers/http/http_server.py: Same
2015-09-22 16:38:40 +05:30
Darshit Shah
c387db6451 Do not test for impossible qop value
* http.c (digest_authentication_encode): Wget already errors out if
    qop != "auth". Then it makes no sense to test for qop == "auth-int"
    later on. Currently, Wget does not support the "auth-int" qop value
    and till nobidy requests, it may remain so.
2015-09-22 16:36:40 +05:30
Darshit Shah
12dfc03116 Fix #46024. Support RFC 2069 Digest Authentication
* http.c (digest_authentication_encode): Some servers are still
    using the obsolete RFC 2069 Digest Authentication. Allow Digest
    authentication without the qop parameter for this.

    Reported-by: Andreas Longwitz  <longwitz@incore.de>
2015-09-22 15:41:22 +05:30
Darshit Shah
3ea0beec6f Revert "Disable progress bar when wget is backgrounded (trivial patch)"
This reverts commit e624732563.
2015-09-21 19:41:38 +05:30
Giuseppe Scrivano
b50300a7a2 NEWS: cite FTPS support 2015-09-20 15:15:12 +02:00
Ander Juaristi
f8901af4e0 Added support for FTPS
* doc/wget.texi: updated documentation to reflect the new FTPS functionality.
 * src/ftp-basic.c (ftp_greeting): new function to read the server's greeting.
   (ftp_login): greeting code was previously here. Moved to ftp_greeting to
   support FTPS implicit mode.
   (ftp_auth): wrapper around the AUTH TLS command.
   (ftp_ccc): wrapper around the CCC command.
   (ftp_pbsz): wrapper around the PBSZ command.
   (ftp_prot): wraooer around the PROT command.
 * src/ftp.c (get_ftp_greeting): new static function.
   (init_control_ssl_connection): new static function to start SSL/TLS on the
   control channel.
   (getftp): added hooks to support FTPS commands (RFCs 2228 and 4217).
   (ftp_loop_internal): test for new FTPS error codes.
 * src/ftp.h: new enum 'prot_level' with available FTPS protection levels +
   prototypes of previous functions. New flag for enum 'wget_ftp_fstatus' to track
   whether the data channel has some security mechanism enabled or not.
 * src/gnutls.c (struct wgnutls_transport_context): new field 'session_data'.
   (wgnutls_close): free GnuTLS session data before exiting.
   (ssl_connect_wget): save/resume SSL/TLS session.
 * src/http.c (establish_connection): refactor ssl_connect_wget call.
   (metalink_from_http): take into account SCHEME_FTPS as well.
 * src/init.c, src/main.c, src/options.h: new command line/wgetrc options.
   (main): in recursive downloads, check for SCHEME_FTPS as well.
 * src/openssl.c (struct openssl_transport_context): new field 'sess'.
   (ssl_connect_wget): save/resume SSL/TLS session.
 * src/retr.c (retrieve_url): check new scheme SCHEME_FTPS.
 * src/ssl.h (ssl_connect_wget): refactor. New parameter of type 'int *'.
 * src/url.c. src/url.h: new scheme SCHEME_FTPS.
 * src/wget.h: new FTPS error codes.
 * src/metalink.h: support FTPS scheme.
2015-09-14 10:16:44 +02:00
Christian Neukirchen
e624732563 Disable progress bar when wget is backgrounded (trivial patch)
* src/progress.c (create_image): progress only when in foreground

Sometimes I start wget, but the remote site is too slow, so I rather
want to run it in background, however when I simply use job control
for that, wget will keep spewing the progress bar all over my
terminal.  I have found the SIGHUP/SIGUSR1 feature to redirect output
to a log file, but I think the following small patch is even more
useful, since the progress bar will simply resume when wget is
foregrounded again (also, the final message is still printed to the
terminal in any case):
2015-09-10 10:26:29 +02:00
Hubert Tarasiuk
f2cb6e050a Add information about libmetalink and GnuPG
* README.checkout: Optional dependencies and URL references.
2015-09-04 08:01:11 +02:00
Hubert Tarasiuk
84b9abbf3c Do not free Metalink structure if not initialized
* src/main.c (main): Move metalink_delete to the conditional block.
2015-09-02 09:17:37 +02:00
Ander Juaristi
58917dcde1 Updated HSTS documentation
* doc/wget.texi: updated HSTS documentation.

   Reported-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2015-09-01 13:50:40 +02:00
Ander Juaristi
ab47d9fa3a Extra debug traces for HSTS.
* src/main.c (load_hsts, save_hsts): added DEBUGP() calls to signal
   reads and saves of the HSTS database file.
2015-09-01 13:50:40 +02:00
Darshit Shah
187edb604a Fix coding style violation in last commit
* http.c (test_parse_range_header): Declare loop variable
    explicitly. Not in gnu99 standard.
2015-08-31 21:04:54 +05:30
Darshit Shah
b06fca60ac Add unit test for parse_content_range() method
* http.c (test_parse_range_header): New function to test the
    function for parsing the HTTP/1.1 Content-Range header.
    * test.[ch]: Same
    * http.c (parse_content_range): Fix parsing code. Fail on scenarios
    mentioned in rfc 7233.
2015-08-30 21:34:32 +05:30
Tim Rühsen
c809398e8c Fix null pointer dereference
* src/metalink.c (gpg_skip_verification):
  Check output_stream before fclose
2015-08-30 14:17:47 +02:00
Tim Rühsen
88a1a79bc1 Fix leaks found by Coverity
* src/http.c (parse_strict_transport_security): Free c_max_age
             (open_output_stream): Fix indentation
* src/iri.c (locale_to_utf8): Free new
2015-08-30 14:10:25 +02:00
Tim Rühsen
398699c438 Fix two leaks foudn by Coverity
* src/http.c (gethttp): Do not leak 'message'.
* src/main.c (format_and_print_line): Do not leak 'line_dup'.
2015-08-29 22:35:29 +02:00
Tim Rühsen
d3504b9261 Fix resource leak discovered by Coverity
* src/retr.c (retrieve_url): Don't leak local_file.
2015-08-29 22:15:34 +02:00
Darshit Shah
6b5acff566 Fix memory leaks in unit-test
* hsts.c (get_hsts_store_filename): Free the homedir value
    (close_hsts_test_store): Actually free the store struct too
    (test_hsts_new_entry): Pass store to close_hsts_test_store()
    (test_hsts_url_rewrite_superdomain): Same
    (test_hsts_url_rewrite_congruent): Same
    (test_hsts_read_database): Same and homedir and store filename
    * http.c (test_parse_content_disposition): Free the returned
    filename
    * url.c (test_append_uri_pathel): Free allocated string
2015-08-29 22:52:49 +05:30
Darshit Shah
5c4489db9b Fix mixed-indentation in http.c
* http.c: Fix mix indentation. Visual change only.
2015-08-29 09:45:13 +05:30
Tim Rühsen
7bed9a6f8f Suppress debug output when strings may contain password
* iri.c (do_conversion): Do not print out converted strings if they
  contain an '@'. That could be an URL with embedded password.

Fixes #45825
2015-08-27 09:55:13 +02:00
Ander Juaristi
d080a70a3a Fix resource leak.
* src/http.c (parse_strict_transport_security): Freed memory to avoid resource leak.
   Comply with GNU coding style.
2015-08-26 17:50:26 +05:30
Tim Rühsen
2d2ddb25d8 Fix typo in NEWS
* NEWS: Change typo --accept-reject into --accept-regex

Reported-by: grarpamp <grarpamp@gmail.com>
2015-08-22 22:34:33 +02:00
Jookia
030c3379d1 Clarify that links are being converted.
* src/convert.c: Add 'links in' after 'Converted %d' and 'Converting %s'.
2015-08-21 20:58:55 +02:00
Jookia
d3d8de8223 Removed useless TODOs.
* testenv/Test--reject-log.py: Remove TODOs.
2015-08-21 20:58:39 +02:00
Miquel Llobet
e04c5989ff Fixed #44516 -o- not logging to stdout
src/log.c (log_init): check for hypen on filename, set stdout
2015-08-16 00:20:20 +05:30
Daniele Calore
12bae50b28 Fix #40426: Allow -r -O- only if FILE is regular
* main.c: added check of "-r -O FILE" option combination
    allow only if FILE is a regular file (bug #40426)
2015-08-16 00:16:12 +05:30
Darshit Shah
f71887bbe5 Fix var name conflicts with math.h and wingdi.h
* src/recur.c (reject_reason): Rename all enum members to WG_RR_xx.
    * src/recur.c (retrieve_tree, download_child,
    write_reject_log_reason): Same
2015-08-15 15:43:33 +05:30
Tim Rühsen
84c405e690 Let bootstrap/autoreconf work without GPGME installed
* configure.ac: Check for existance of AM_PATH_GPGME
2015-08-14 10:17:52 +02:00
Tim Rühsen
075d755696 Fix IP address exposure in FTP code
* src/ftp.c (getftp): Do not use PORT when PASV fails.
* tests/FTPServer.px: Add pasv_not_supported server flag.
* tests/Makefile.am: Add Test-ftp-pasv-not-supported.px
* tests/Test-ftp-pasv-not-supported.px: New test

Fix IP address exposure when automatically falling back from
passive mode to active mode (using the PORT command). A behavior that
may be used to expose a client's privacy even when using a proxy.
2015-08-11 17:38:33 +02:00
Tim Rühsen
7578e47d49 Fix C89 compliancy in HSTS test code
* src/hsts.c (test_hsts_new_entry):
  Move variable assignment before code
2015-08-07 14:03:00 +02:00
Tim Rühsen
3a708f7ef8 Fix C89 compliancy in latest code
* src/recur.c: Declare variables before code
  (write_reject_log_url):
    Use const keyword where appropriate
    Use the 'default' switch statement
    Use xfree() instead of free()
    Renamed variable f -> fp
  (write_reject_log_reason):
    Use const keyword where appropriate
    Use the 'default' switch statement
    Renamed variable f -> fp
    Renamed variable r -> reason
2015-08-07 13:42:30 +02:00
Tim Rühsen
474935665e Remove redundant definition of _GNU_SOURCE
* src/warc.c: Remove definition of _GNU_SOURCE

_GNU_SOURCE is already defined in config.h
2015-08-07 13:24:14 +02:00
Giuseppe Scrivano
f8519b52f0 NEWS: update 2015-08-07 08:32:34 +02:00
Jookia
98272d2c8d Rewrite the --rejected-log test using the new framework.
* tests/Test--rejected-log.px: Remove old test.
 * testenv/Test--rejected-log.py: Create new test.
2015-08-07 08:20:47 +02:00
Jookia
7e5079c40f Replace variables before comparing expected files.
* expected_files.py: Use formatted_content instead of file.content.
2015-08-07 08:20:46 +02:00
Jookia
e4db00d74d Add option to write URL rejections to a tab-delimited CSV log.
* main.c: Add "--rejected-log" option.
 * init.c: Add "rejectedlog" command.
 * options.h: Add "rejected_log" parameter string.
 * wget.texi: Add brief documentation on new --rejected-log option.
 * recur.c: Optionally log details of URLs not traversed.
   Add reject_reason enum.
   (download_child_p -> download_child): Return a reject_reason.
   (descend_redirect_p -> descend_redirect): Return a reject_reason.
   (retrieve_tree): Support logging reasons for rejection.
   Add write_reject_log_header that writes a CSV format header to a file.
   Add write_reject_log_url that writes a url struct to a file in CSV format.
   Add write_reject_log_reason that writes the URL and parent URL as well as the
   rejection reason to a CSV file.
 * Test--rejected-log.px: Add a basic test for the --rejected-log command.
 * tests/Makefile.am: Run Test--rejected-log.px.

This allows you to figure out why URLs are being rejected and some context
around it. CSV is used as the output format since it can be used easily parsed,
it's delimited by tabs instead of commas to allow using all (quoted) URL
characters and includes column names which may be used for compatibility.
2015-08-06 08:10:55 +02:00
Tim Rühsen
670eb924e7 Fix memory leak in HSTS code
* src/main.c (get_hsts_database): Free 'home' variable
2015-08-04 17:41:54 +02:00
Tim Rühsen
5d55018ce6 void uninitialized variable in metalink code
* src/metalink.c: Init retr_err with METALINK_MISSING_RESOURCE
* src/wget.h: Add enum METALINK_MISSING_RESOURCE
2015-08-04 17:24:59 +02:00
Darshit Shah
4e56a91001 Fix function name collision with OpenSSL library
* src/utils.[ch], src/http.c, src/metalink.c: Rename function
    hex_to_string() to wg_hex_to_string sine it collides with a
    similarly named function in OpenSSL Library.
2015-07-24 23:52:43 +05:30
Darshit Shah
595f219a17 Fix configure options for metalink
* configure.ac: Ensure metalink support can be properly disabled
2015-07-24 23:42:20 +05:30
Alex Henrie
b6e242cd6f Make the filename marquee a proper marquee
* src/progress.c: Start the marquee in the middle of the available space
  and do not restart it until all of the text has scrolled out of view.
2015-07-22 16:52:20 +05:30
Giuseppe Scrivano
207006ef25 NEWS: cite HSTS 2015-07-20 16:31:17 +02:00
Giuseppe Scrivano
843634db59 Fix metalink tests
testenv/Test-metalink-http.py: initialize HTTP test server
testenv/Test-metalink-xml.py: initialize HTTP test server
2015-07-20 16:29:05 +02:00
Ander Juaristi
54058d2b18 Enhancements in testsuite engine + new HSTS test.
* testenv/Makefile.am: added new test 'Test-hsts.py'.
 * testenv/Test-hsts.py: new test for HSTS.
 * testenv/conf/domains.py: new hook to override domain list.
 * testenv/test/base_test.py: (__init__): new optional parameter
   for tests 'req_protocols'.
   (get_domain_addr): set the instance variables 'addr' and 'port'.
   Return address as an array (domain, port) instead of string.
   (gen_cmd_line): take into account domain and port.
 * testenv/test/http_test.py (__init__): new optional parameter
   'req_protocols'.
   (setup): new function. Call to server_setup() decoupled from
   begin() and moved here.
   (begin): call to superclass to maintain backward compatibility.
   Removed call to server_setup().

This patch adds a new parameter to the test suite called 'req_protocols',
and a new function called 'setup'. The ability for tests to be able to set some
extra parameters such as the actual requested protocols (with 'req_protocols')
became obvious when support for HSTS was added to Wget, where the requested URI
and the actual executed URI do not have to be the same. This new parameter is optional
and if not specified, the test suite behaves as before. Also, the new function 'setup'
is provided as a means to start the test HTTP server, but not launch the test yet
(this is done when calling 'begin', as usual), in case we want to query the address
and port in which the test server listens. If 'setup' is not called, it is automatically
invoked when calling 'begin'. With these measures, we preserve backward-compatibility with
existing tests.
2015-07-20 16:06:40 +02:00
Ander Juaristi
b60131a399 Added support for HSTS.
* Makefile.am: Added new source files hsts.c and hsts.h.
 * http.c (parse_strict_transport_security): new function for STS header
   parsing.
   (gethttp): update the HSTS store.
 * http.h: new include "hsts.h".
 * init.c: new options --hsts and --hsts-file.
 * main.c (get_hsts_database, load_hsts, save_hsts): new functions.
   New options --no-hsts and --hsts-file added to help.
   (main): load and save HSTS store.
 * options.h: new variables for supporting --hsts and --hsts-file.
 * retr.c (retrieve_url): rewrite the URI according to the HSTS policy before
   entering http_loop.
 * test.c, test.h: new unit tests for HSTS.
 * utils.c, utils.h (countchars): new function.
 * wget.h: new preprocessor check.
 * hsts.c, hsts.h: new files with the HSTS engine implementation.

Added support for HTTP Strict Transport Security (HSTS), as defined by RFC
6797.
2015-07-20 15:55:57 +02:00
Giuseppe Scrivano
fc8a545bfd NEWS: cite metalink support 2015-07-20 15:50:29 +02:00
Giuseppe Scrivano
9e12b8ca39 fix compiler warnings
* src/utils.h: Include <stdlib.h>
* src/recur.c: Include "exits.h"
2015-07-20 15:37:52 +02:00
Hubert Tarasiuk
4c3043d19d Test preferred location in Metalink-over-HTTP test case.
* testenv/Test-metalink-http.py: Ensure preferred location is handled
properly.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
6064f21c66 Geolocation support for Metalink resources.
* doc/wget.text: Add information about --preferred-location.
* src/init.c: Add --preferred-location option.
* src/main.c (option_data): Handle --preferred-location argument.
(main): Sort resources based on location if requested.
* src/metalink.c (metalink_res_cmp): Compare based on location if
priority and preference are equal.
* src/options.h (options): Add preferred_location option.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
97389a7497 Support at most one file signature. Adapt comments to libmetalink 0.13.
* src/metalink.c (retrieve_from_metalink): Add comment about new
libmetalink version. Do not iterate over signatures - support just one.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
225a87d4a2 Move some Metalink-related code from http.c to metalink.c.
* src/http.c: Move find_key_value, has_key, find_key_values.
* src/metalink.c: To here.
* src/metalink.h: Make them non-static and add prototypes here.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
92a889b278 Unit test for find_key_values.
* src/http.c: Add test_find_key_values.
* src/test.c (main): Run new test.
* src/test.h: Add test_find_key_values.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
1113e78534 Unit test for has_key.
* src/http.c: Add test_has_key.
* src/test.c (main): Run new test.
* src/test.h: Add test_has_key.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
70cbd59ed6 Unit test for find_key_value.
* src/http.c: Add test_find_key_value.
* src/test.c (main): Run new test.
* src/test.h: Add test_find_key_value.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
0e7aff7623 Test case for Metalink over HTTP.
* testenv/Test-metalink-http.py: New test.
* testenv/Makefile.am: Add to test list.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
792dd09a87 Support multiple headers with same name in Python test suite.
* testenv/README: Describe how to use repeated header name.
* testenv/server/http/http_server.py (finish_headers): Send all
values from list if the header value is a Python list.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
a4f5ced797 Test case for Metalink in XML.
* testenv/Test-metalink-xml.py: New test.
* testenv/Makefile.am: Add file for automake.
2015-07-20 15:31:06 +02:00
Hubert Tarasiuk
05c30c3b1b Start HTTP test only when calling begin().
* testenv/test/http_test.py: Move self.do_test() from __init__ to
begin().
2015-07-20 15:30:39 +02:00
Hubert Tarasiuk
37b58e3976 Metalink support.
* bootstrap.conf: Add crypto/sha256
* configure.ac: Look for libmetalink and GPGME
* doc/wget.texi: Add --input-metalink and --metalink-over-http
options description.
* po/POTFILES.in: Add metalink.c
* src/Makefile.am: Add new translation unit (metalink.c)
* src/http.c (http_stat): Add metalink field.
(free_stat): Free metalink field.
(find_key_value): Find value of given key in header string.
(has_key): Check if token exists in header string.
(find_key_values): Find all key=value pairs in header string.
(metalink_from_http): Obtain Metalink metadata from HTTP response.
(gethttp): Call metalink_from_http if requested.
(http_loop): Request Metalink metadata from HTTP response if should be.
Fall back to regular download if no Metalink metadata found.
* src/init.c: Add --input-metalink and --metalink-over-http options
* src/main.c (option_data): Handle --input-metalink and
--metalink-over-http cmd arguments.
(print_help): Print --input-metalink option description.
(main): Retrieve files from Metalink file
* src/metalink.c (retrieve_from_metalink): Download files described by
metalink.
(metalink_res_cmp): Comparator for resources priority-sorting.
* src/metalink.h: Create header for metalink.c
(RES_TYPE_SUPPORTED): Define supported resources media.
(DEFAULT_PRI): Default mirror priority for Metalink over HTTP.
(VALID_PRI_RANGE): Valid priority range.
* src/options.h (options): Add input_metalink option and metalink_over_http
options.
* src/utils.c (hex_to_string): Convert binary data to ASCII-hex.
* src/utils.h (hex_to_string): Add prototype.
* src/wget.h: Add metalink-related error enums
Add METALINK_METADATA flag for document type.
2015-07-20 15:30:39 +02:00
Romain Bentz
80303366ae Add NULL value check to fix #45289
* src/recur.c (retrieve_tree): Check return value of url_parse()
2015-07-15 18:10:08 +02:00
Tim Rühsen
bd0ffcf8bc Let HTTPS tests XFAIL when no TLS support configured
* configure.ac: Export WITH_SSL for use in Makefile.am
* testenv/Makefile.am: Add HTTPS tests to XFAIL_TESTS when !WITH_SSL

Reported-by: Ander Juaristi <ajuaristi@gmx.es>
2015-07-14 07:54:03 +02:00
Tim Rühsen
25c9b462bf Change function params to const in src/iri.[ch]
* iri.h, iri.c: Added const attribute for params of parse_charsset(),
	check_encoding_name(), idn_encode(), idn_decode(),
	remote_to_utf8(), set_uri_encoding(), set_content_encoding().
2015-07-01 17:15:10 +02:00
Tim Rühsen
77f5a27e65 Work around a libidn <= 1.30 vulnerability
* src/iri.c: Add _utf8_is_valid() to check UTF-8 sequences before
  passing them to idna_to_ascii_8z().
2015-07-01 17:15:05 +02:00
Ángel González
ae58d8a78b Fix wgetrc filename creation for Windows
* init.c/wgetrc_file_name: Remove obsolete code in WINDOWS code path

Reported-by: Gisle Vanem <gvanem@yahoo.no>
2015-06-27 21:32:48 +02:00
Darshit Shah
58702ffd4f Add valgrind suppression files for HTTPS tests
* testenv/test/base_test.py: Use Valgrind SSL suppressions file for
    tests
    * testenv/valgrind-suppression-ssl, tests/valgrind-suppression-ssl:
    Add new suppression files to suppress OpenSSL errors in valgrind
    * tests/test-proxied-https-auth.px: Use the valgrind SSL
    suppressions file for the test
    * tests/test-proxied-https-auth-keepalive.px: Same
2015-06-16 20:31:00 +05:30
Darshit Shah
103f940950 contrib/check-hard: Indentation and spacing cleanup
* contrib/check-hard: Reduce the amount of text output to the
    screen. Also implement some indentation and whitespace cleanups.
2015-06-15 01:35:53 +05:30
Tim Rühsen
5f0818d9f1 Fix usage of CFLAGS in contrib/check-hard
* contrib/check-hard: Set CFLAGS per command line instead of using export.

'make distcheck' changes CFLAGS. So using ./configure -C together with
exported CFLAGS fails. Setting CFLAGS per command line works smoothly.
2015-06-14 20:30:07 +02:00
Tim Rühsen
c6ac51d5bc Move test_* function protoypes from test.c to test.h
* src/test.c: Remove test_* function prototypes, make tests_run static
* src/test.h: Add test_* function protoypes
2015-06-13 22:34:36 +02:00
Giuseppe Scrivano
fd3a3245eb NEWS: cite --if-modified-since 2015-05-23 14:54:17 +02:00
Giuseppe Scrivano
48acb6693d gnulib: update gnulib 2015-05-23 14:51:52 +02:00
Hubert Tarasiuk
885eaaa214 Include --if-modified-since option in user manual.
* doc/wget.texi: Add --if-modified-since section.
2015-05-22 11:08:30 +02:00
Hubert Tarasiuk
8a8d138dcc Support If-Modified-Since header in timestamping mode.
* src/wget.h: Add IF_MODIFIED_SINCE enum for dt. Add TIMECONV_ERR
enum to uerr_t.
* src/http.c (time_to_rfc1123): Convert time_t do http time.
* src/http.c (initialize_request): Include If-Modified-Since header
if appropriate.
* src/http.c (set_file_timestamp): Separate this code from check_file_output.
* src/http.c (check_file_output): Use set_file_timestamp.
* src/http.c (gethttp): Handle properly 304 return code and 200 if server
ignores If-Modified-Since headers.
* src/http.c (http_loop): Load filename to hstat if condget was requested,
use IF_MODIFIED_SINCE if requested and current timestamp can be obtained.
2015-05-22 11:08:30 +02:00
Hubert Tarasiuk
0e8d2d4251 Add --if-modified-since option
* src/init.c: Add to commands array.
* src/main.c: Add to cmdline_option. Add to help message.
* src/options.h: Add to options struct.
2015-05-22 11:08:30 +02:00
Hubert Tarasiuk
be4f91737a Add test for condget requests.
* testenv/Test-condget.py: the test
* testenv/Makefile.am: add to tests list
2015-05-22 11:08:30 +02:00
Hubert Tarasiuk
901bc98edf Support conditional GET in testenv server.
* src/exc/server_error.py: Add exception for GET to HEAD fallback.
* src/server/http/http_server.py: Do not send body if 304 return
code requested for a file.
2015-05-22 11:08:30 +02:00
Hubert Tarasiuk
e397a48f6a Implement timestamp support for local files in testenv
* testenv/README: Change timestamp format definition
* testenv/conf/local_files.py: Set proper timestamps
2015-05-22 11:08:30 +02:00
Pär Karlsson
83537f2415 Fix undeclared loop variable in Perl test suite
Reported-by: Hubert Tarasiuk <hubert.tarasiuk@gmail.com>
2015-05-20 10:04:07 +02:00
Ander Juaristi
8682c2612f Make sure Wget does not unescape reserved chars.
* testenv/Test-reserved-chars.py: New file.

* testenv/Makefile.am: Added new test Test-reserved-chars.py.

When following redirections, Wget should not unescape the reserved
characters that might appear in target URLs.
2015-05-12 21:24:11 +02:00
Ander Juaristi
b0820d553b Fixed incorrect handling of reserved chars.
* src/iri.c (do_conversion): Call url_unescape_except_reserved,
instead of url_unescape.

* src/url.c (url_unescape_1): New static function.
(url_unescape): Calls url_unescape_1 with mask zero. Preserves
same behavior as before. Only code changes.
(url_unescape_except_reserved): New function.

* src/url.h: Added prototype for url_unescape_except_reserved().

When the locale is US-ASCII, URIs that contain special characters
in them are converted to IRIs according to RFC 3987, section 3.2
"Converting URIs to IRIs".
2015-05-12 21:24:06 +02:00
Darshit Shah
b6b1388fb7 Fix documentation for update_speed_ring()
* progress.c (update_speed_ring): The comment for the function
    incorrectly stated that the function uses thirty samples from the
    past instead of twenty.

    Reported-By: Yi Li <lovelylich@gmail.com>
2015-05-07 11:29:07 +05:30
Darshit Shah
9b1dd6dab8 Remove shadowed variable in http.c
* http.c (gethttp): Rename err to conn_err to prevent shadowed
    variable
2015-05-04 21:45:26 +05:30
Steven Schubiger
1cc835dc5b paramcheck: use explicit quoting for here-docs
* util/paramcheck.pl: Adjust here-docs
2015-05-04 10:13:24 +05:30
Tim Ruehsen
6b8dfe1d6e Fix format specifier warning
* src/utils.c (aprintf): Use %d for int argument
2015-05-03 21:18:47 +02:00
Nikolay Merinov
0e6d6ca963 Fix timestamping and continue behaviour with ftp protocol.
* src/ftp.c (ftp_loop_internal): Add option `force_full_retrieve' that force to
retrieve full file.
(ftp_retrieve_list): Pass `true' as `force_full_retrieve' option to
`ftp_loop_internal' if we want to download file with newer timestamp than local
copy.
2015-05-01 00:28:08 +02:00
Rohit Mathulla
3765a1b266 openssl: Read cert from private key file when needed
* src/openssl.c (ssl_init): Assign opt.cert_{file, type}
  from opt.private_key(_type)
2015-04-27 19:52:18 +02:00
Rohit Mathulla
8654f7e2e7 Fix double free bug in SSL code
* src/openssl.c, src/gnutls.c (ssl_init): Copy options using xstrdup
2015-04-27 19:48:51 +02:00
Hubert Tarasiuk
566696cb82 Single exit point and common cleanup code in gethttp
* src/http.c (gethttp): Common cleanup for type, message,
  req, resp, head.  Single exit point.
2015-04-20 10:54:34 +02:00
Tim Rühsen
bebe462a67 Silence warning in perl test suite
* tests/WgetTests.pm: Use string comparisons for $valgrind variable
2015-04-17 22:42:59 +02:00
Tim Rühsen
c579c7bf1e Check memory allocations in WARC code
* src/warc.c: Remove some memory allocations,
              use xmalloc instead of malloc

Reported-by: Bill Parker <wp02855@gmail.com>
2015-04-17 22:42:59 +02:00
Tim Rühsen
4dde3e200f Add more const usage to function params
* warc.c, warc.h: Add const specifier to several function args
2015-04-17 22:42:59 +02:00
Darshit Shah
8e0dd0d870 PEP8'ify the Python Test Suite
* testenv/conf/{__init__,authentication,files_crawled,
      hook_sample,reject_header,server_files}.py: Aesthetic changes to
      meet Python PEP8 guidelines
    * testenv/exc/{server_error,test_failed}.py: Same
    * testenv/misc/{colour_terminal,wget_file}.py: Same
    * testenv/server/http/http_server.py: Same
    * testenv/test/base_test.py: Same
2015-04-14 10:59:17 +05:30
Ander Juaristi
c6af2fddee Improved test suite documentation
* README.checkout: Added reference to Python. New section
  "Testing and development". Updated information about test suites.
2015-04-13 19:36:39 +02:00
Ander Juaristi
e7e3227b34 Added support for GDB in Python tests
* base_test.py (gen_cmd_line): Check GDB_TESTS environment variable.
2015-04-13 19:32:57 +02:00
Tim Ruehsen
5c5d45ae49 Added GDB support to Perl tests
* WgetTests.pm (run): Check GDB_TESTS environment variable.
2015-04-13 19:29:43 +02:00
Hubert Tarasiuk
f4072e5d0b Add Valgrind suppression for libidn.so at idna_to_ascii_4z
* tests/WgetTests.pm (run): Include suppression file when running Valgrind.
* tests/valgrind-suppressions: Add suppression for idn_to_ascii_4z.
* tests/Makefile.am: Add valgrind-suppressions to EXTRA_DIST.
2015-04-11 23:16:32 +02:00
Ángel González
bef5945202 Remove memory leak in idn_encode.
* src/iri.c (idn_encode): Free buffer from remote_to_utf8
when needed; give meaningful names to variables;
remove excessive comment.
2015-04-11 21:55:17 +02:00
Hubert Tarasiuk
ac40b84ee1 Fix error in free_vec.
* src/utils.c (free_vec): Increment pointer instead of its value.

Reported-by: Gisle Vanem <gvanem@yahoo.no>
2015-04-10 18:06:14 +02:00
Ángel González
45463eaad7 Fix const usage in iri.c
* src/iri.c (remote_to_utf8): Do not qualify with const the output pointer.
(do_conversion): Use the provided input parameter as const.
(idn_encode): casts to remote_to_utf8 parameters are no longer needed.
* src/iri.h: Adjusted remote_to_utf8 prototype.
* src/url.c: It is no longer necessary to cast new_url to const char.
2015-04-10 10:23:01 +02:00
Miquel Llobet
d03b40e31e Fixed #44628 honoring RFC 6266 content-disposition
src/http.c (parse_content_disposition): stores filename* and filename
separately and choses filename* if available.
(test_parse_content_disposition): added new tests.
2015-04-06 10:30:30 +02:00
Giuseppe Scrivano
268e6aef72 NEWS: cite last change 2015-04-02 15:39:02 +02:00
Steven M. Schweda
5efb24e4a2 Add option to restrict filenames used VMS.
* src/options.h (enum restrict_files_os): Define "restrict_vms".
* src/init.c (defaults) [__VMS]: Set "opt.restrict_files_os" to
"restrict_vms".
(cmd_spec_restrict_file_names): honor "vms".
* src/url.c (filechr_not_unix): Define "filechr_not_vms".
(filechr_table): Update for VMS.
(append_uri_pathel): Honor opt.restrict_files_os.
(FN_QUERY_SEP): Update for VMS.
(FN_QUERY_SEP_STR): Update for VMS.
2015-04-02 15:36:42 +02:00
Hubert Tarasiuk
eae8b1d565 Change semantics of resp_free and request_free in http.c
* src/http.c (resp_free): Change the semantics of this function.
(request_free): Change the semantics of this function.
(initialize_request): Adjust request_free call.
(establish_connection): Adjust request_free, resp_free calls.
(gethttp): Adjust request_free, resp_free calls.
2015-04-01 17:01:07 +02:00
Hubert Tarasiuk
045463b814 Do not free request in establish_connection; do it in gethttp
* src/http.c (establish_connection): Do not free request here (it is
* never allocated here).
* src/http.c (gethttp): Free request before returning if error in
* establish_connection encountered.
2015-04-01 17:01:07 +02:00
Hubert Tarasiuk
621c313b94 Transform read_header label and goto into a loop
* src/http.c (gethttp): Replace label and goto statement with a do
loop.
2015-04-01 17:00:40 +02:00
Hubert Tarasiuk
52a7d0ad85 Factor out set_content_type function from gethttp
* src/http.c (gethttp): Move some code in...
(set_content_type): ... a new function.
2015-03-31 17:00:07 +02:00
Giuseppe Scrivano
59e9ef00e6 Factor out some gethttp code
* src/http.c (gethttp): Move some code in...
(open_output_stream): ... a new function.
2015-03-18 12:09:55 +01:00
Giuseppe Scrivano
14bbc18512 Factor out some auth gethttp code
* src/http.c (gethttp): Move some code in...
(check_auth): ... a new function.
2015-03-18 12:09:55 +01:00
Giuseppe Scrivano
8aa63e482e Factor out some gethttp code
* src/http.c (gethttp): Move some code in...
(check_file_output): ... a new function.
2015-03-18 12:09:55 +01:00
Giuseppe Scrivano
0bc2757713 Factor out some connection initialization code for gethttp
* src/http.c (gethttp): Move some initialization code in...
(establish_connection): ... a new function.
2015-03-18 12:09:55 +01:00
Giuseppe Scrivano
f8abb9dd00 Factor out some proxy initialization code for gethttp
* src/http.c (gethttp): Move some initialization code in...
(initialize_proxy_configuration): ... a new function.
2015-03-18 12:09:55 +01:00
Giuseppe Scrivano
29850e77d0 Factor out some initialization code for gethttp
* src/http.c (gethttp): Move some initialization code in...
(initialize_request): ... a new function.
2015-03-18 12:09:54 +01:00
Tim Ruehsen
799c545722 src/ftp.c: make sure warc_tmp becomes closed before return
Reported-by: Coverity bug #1188044
2015-03-18 10:46:11 +01:00
Tim Ruehsen
014b1d6041 src/http.c: fix error return of digest_authentication_encode()
Reported-by: Coverity bug #1188036
2015-03-18 10:46:05 +01:00
Rohan Prinja
8d4bb928b9 Convert wget.texi to UTF-8
* doc/wget.texi: convert to UTF-8 by adding @documentencoding
* doc/Makefile.am: Pass argument --utf8 to pod2man.
2015-03-17 09:52:23 +01:00
Ander Juaristi Alamos
d0f406a13f * doc/wget.texi: The default is GnuTLS, not OpenSSL. 2015-03-16 22:46:08 +01:00
Darshit Shah
87b52e510c testenv/http_server: Allow overriding Headers
We would like to override existing headers in the response from the
server to allow the test cases to define their own headers. This patch
allows this behaviour through the use of the add_header() method while
also allowing sending multiple headers of the same name.
2015-03-16 23:24:14 +05:30
Darshit Shah
cc9f76c5a4 retr.c: Fix memory leak in retrieve_from_file()
Reported by: Coverity Bug 1188045
2015-03-14 16:48:30 +05:30
Darshit Shah
53b22974cb html-url.c: Fix potential memory leaks
Reported by: Coverity Bug 1188050
2015-03-14 16:48:30 +05:30
Darshit Shah
7d5a7ef9ca main.c: Fix two potential memory leaks
Reported by: Coverity bug 1188048
2015-03-14 16:48:30 +05:30
Darshit Shah
735cc220e3 retr.c: Fix two memory leaks when proxy URL is bad
Reported by: Coverity bug 1188047
2015-03-14 16:48:29 +05:30
Darshit Shah
524f26a200 Docs: --post-file is binary data
Wget considers the file mentioned in the --post-file argument as a
binary file and does not strip any control characters. The lack of this
information in the documentation can cause a lot of headaches debugging
for a simple issue
2015-03-13 23:51:59 +05:30
Giuseppe Scrivano
16f1fb1d1f maint: update copyright year ranges to include 2015 2015-03-09 16:32:01 +01:00
Giuseppe Scrivano
b74ac4c7e0 NEWS: Prepare new development cycle 2015-03-09 16:28:16 +01:00
Yousong Zhou
91e9a20752 Fix --content-on-error option handling.
* src/http.c: Log --content-on-error downloads.
* src/retr.c (retrieve_url): Register the download of an error page
when --content-on-error is specified.
2015-03-09 11:45:01 +01:00
Yousong Zhou
4a214bc9a3 testenv: add test case Test--convert-links--content-on-error.py.
* testenv/Makefile.am: Register the new test.
* testenv/Test--convert-links--content-on-error.py: Add test case for
the combination of --convert-links and --content-on-error.py.
2015-03-09 11:42:11 +01:00
Yousong Zhou
b7b6d7fd89 testenv: fix http_server.py with Response and Authentication.
* testenv/exc/server_error.py: Try writing file content for GET
request even if there is a Response rule present.
* testenv/server/http/http_server.py: Likewise.
2015-03-09 11:41:08 +01:00
Yousong Zhou
3a00b37bc2 testenv: improve color output a bit.
* testenv/misc/colour_terminal.py: Only print color codes when stdout
isatty().
2015-03-09 11:40:44 +01:00
Yousong Zhou
adcc793a26 testenv: typo and style fix.
* testenv/server/http/http_server.py(BaseTest): Add docstring; use raw
string for regex.
* testenv/server/http/http_server.py(_Handler): Typo fix.
* testenv/conf/server_files.py(ServerFiles): Code style change for
readability plus another typo fix.
2015-03-09 11:40:05 +01:00
Giuseppe Scrivano
d94d9cd98b NEWS: tag 1.16.3 2015-03-09 10:01:08 +01:00
Anderson Goulart
882ed28d59 src/main.c (--no-verbose): don't show progress bar
Fixes #44431
2015-03-09 00:44:23 +05:30
Darshit Shah
e316d253fa main.c: Use assertion to test buffer size 2015-03-07 00:38:04 +05:30
Darshit Shah
9dde436dd6 main.c: Need to explicitly disallow show_progress in -q 2015-03-02 21:40:57 +05:30
132 changed files with 7256 additions and 2886 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,7 @@
/.sc-start-sc_bindtextdomain
/.sc-start-sc_prohibit_HAVE_MBRTOWC
/.version
/ABOUT-NLS
/GNUmakefile
/INSTALL
/Makefile
@@ -25,6 +26,7 @@ testenv/*.log
testenv/*.trs
# build-aux/
build-aux/.gitignore
build-aux/ar-lib
build-aux/compile
build-aux/config.guess
build-aux/config.sub

50
.travis.yml Normal file
View File

@@ -0,0 +1,50 @@
sudo: no
language: c
compiler:
- gcc
notifications:
email:
recipients:
- darnir@gmail.com
- bug-wget@gnu.org
on_success: change
on_failure: always
env:
global:
- PERLLIB=$PERLLIB:../../tests
- PERL5LIB=$PERL5LIB:../../tests
matrix:
- SSL=""
- SSL="openssl"
- SSL="gnutls"
addons:
apt:
packages:
- automake
- autoconf
- autopoint
- flex
- texinfo
- pkg-config
- libgnutls-dev
- libssl-dev
- make
- libhttp-daemon-perl
- libio-socket-ssl-perl
- libidn11-dev
- gettext
- texlive
- python3
- valgrind
- language-pack-tr
- language-pack-ru
script:
- make distclean || true
- ./bootstrap
- ./contrib/travis-ci $SSL

1068
ABOUT-NLS

File diff suppressed because it is too large Load Diff

46
NEWS
View File

@@ -1,12 +1,52 @@
GNU Wget NEWS -- history of user-visible changes.
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software
Foundation, Inc.
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free
Software Foundation, Inc.
See the end for copying conditions.
Please send GNU Wget bug reports to <bug-wget@gnu.org>.
* Changes in Wget 1.17.1
* Fix compile error when IPv6 is disabled or SSL is not present.
* Fix HSTS memory leak.
* Fix progress output in non-C locales.
* Fix SIGSEGV when -N and --content-disposition are used together.
* Add --check-certificate=quiet to tell wget to not print any warning about
invalid certificates.
* Changes in Wget 1.17
** Remove FTP passive to active fallback due to privacy concerns.
** Add support for --if-modified-since.
** Add support for metalink through --input-metalink and --metalink-over-http.
** Add support for HSTS through --hsts and --hsts-file.
** Add option to restrict filenames under VMS.
** Add support for --rejected-log which logs to a separate file the reasons why
URLs are being rejected and some context around it.
** Add support for FTPS.
** Do not download/save file on error when --spider enabled
** Add --convert-file-only option. This option converts only the
filename part of the URLs, leaving the rest of the URLs untouched.
* Changes in Wget 1.16.3
** Fix a regression introduced by wget 1.16.2 that --quiet is not
really quiet anymore.
* Changes in Wget 1.16.2
** Native uuid generation on Windows
@@ -114,7 +154,7 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
** Add support for TLS Server Name Indication.
** Accept the arguments --accept-reject and --reject-regex.
** Accept the arguments --accept-regex and --reject-regex.
** The GNU TLS backend honors correctly the timeout value.

View File

@@ -5,7 +5,8 @@ Compiling From Repository Sources
normally present in the distribution tarballs. Therefore, to build GNU
Wget from the sources in the repository, you'll need to have one or
more of the following (note that gettext, OpenSSL, GnuTLS, libidn,
libiconv, libpsl, libpcre and pkg-config are not absolutely required):
libiconv, libpsl, libpcre, pkg-config, libmetalink and GnuPG are not
absolutely required):
* [20]autoconf (currently, GNU Wget requires version 2.61). This is
needed to generate the configure script from configure.in. This is
@@ -23,13 +24,18 @@ Compiling From Repository Sources
* [23]Perl, if you wish to generate the wget(1) manpage, or run the
tests in the tests/ sub directory. Tarball distributions include an
already-generated wget.1 manual. The command "make check" runs the
test suite written in perl. To execute all the tests you need
[24]libwww-perl and libio-socket-ssl-perl perl library. If
test suite written in perl and python (see below). To execute all the tests
you need [24]libwww-perl and libio-socket-ssl-perl perl library. If
"perl -MCPAN -e 'install Bundle::LWP'" fails then you most likely don't
have cpan module installed. First download [25]CPAN and [26]install it.
Then execute "perl -MCPAN -e 'install Bundle::LWP'".
Now "make check" should pass most of the tests in the test suite.
* [45]Python, if you want to run the tests in the testenv/ subdirectory.
Keep in mind that "make check" will try to run all the perl and python
tests. More information about the test suite below in the section
"Testing and development".
* [27]texinfo in order to generate Info, PostScript and/or HTML
documentation. You don't need texinfo in order to generate the
wget(1) manpage; however, note that the manpage does not include
@@ -89,6 +95,10 @@ Compiling From Repository Sources
saved the .pc file. Example:
$ PKG_CONFIG_PATH="." ./configure
* [46]libmetalink is needed to enable Metalink files support.
* [47]GnuPG with GPGME is used to verify GPG-signed Metalink resources.
For those who might be confused as to what to do once they check out
the source code, considering configure and Makefile do not yet exist at
@@ -110,6 +120,8 @@ Compiling From Repository Sources
$ src/wget --version
GNU Wget 1.12-devel (9cb2563197bc)
Testing and development
All developers are requested to enable the assertions on their development
builds to ensure a stable codebase. Assertions are added to state certain
assumptions about the code and its data which all developers should be mindful
@@ -118,6 +130,29 @@ Compiling From Repository Sources
$ ./configure --enable-assert [other configure options]
Both the Perl and Python test suites (test/ and testenv/) include support for GDB and Valgrind.
The environment variables GDB_TESTS and VALGRIND_TESTS are available to
enable such wrappers. If specified, Wget would be run through either of them
during the test. For example:
$ cd testenv
$ VALGRIND_TESTS=1 ./Test-O.py
That would execute Test-O.py test case, but running Wget through Valgrind.
GDB has preference over Valgrind. If both variables have been asserted,
Wget would be run through GDB.
If you run a test case through GDB, please bear in mind that it could give
a false negative. This is because some tests that expect Wget to fail
rely on Wget's return code. However, when run through GDB, its return code
will always be zero, causing the test to claim failure. This wrapper for
GDB is, however, very useful to tackle bugs, allowing one to write a test case
for some specific bug and then using GDB to fix it more easily. Otherwise,
a dedicated server would have to be set up and write a custom CGI just to reproduce
that bug, which might be tedious. Tests should only be run through GDB for that purpose.
Copyright (C) 2008,2010,2014,2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://www.gnu.org/licenses/gpl.html>.
@@ -169,3 +204,6 @@ References
42. http://moinmo.in/GPL
43. http://validator.w3.org/check?uri=referer
44. http://wget.addictivecode.org/WikiLicense
45. https://www.python.org/
46. https://launchpad.net/libmetalink
47. https://www.gnupg.org

View File

@@ -38,6 +38,7 @@ close
connect
dirname
fcntl
flock
fnmatch
futimens
ftello
@@ -64,6 +65,7 @@ mkstemp
mkostemp
crypto/md5
crypto/sha1
crypto/sha256
quote
quotearg
recv

View File

@@ -71,10 +71,13 @@ AC_ARG_WITH([ssl],
[AS_HELP_STRING([--with-ssl={gnutls,openssl}], [specify SSL backend. GNU TLS is the default.])])
dnl Zlib: Configure use iof zlib for compression
dnl Zlib: Configure use of zlib for compression
AC_ARG_WITH([zlib],
[AS_HELP_STRING([--without-zlib], [disable zlib.])])
dnl Metalink: Configure use of the Metalink library
AC_ARG_WITH([metalink],
[AS_HELP_STRING([--with-metalink], [enable support for metalinks.])])
dnl
dnl Process features
@@ -177,7 +180,7 @@ dnl
dnl Gettext
dnl
AM_GNU_GETTEXT([external],[need-ngettext])
AM_GNU_GETTEXT_VERSION([0.17])
AM_GNU_GETTEXT_VERSION([0.18.1])
AC_PROG_RANLIB
@@ -475,6 +478,34 @@ else
fi
fi
dnl
dnl Check for libmetalink
dnl
AS_IF([test x"$with_metalink" != xno], [
PKG_CHECK_MODULES([METALINK], libmetalink, [
LIBS="$METALINK_LIBS $LIBS"
CFLAGS="$METALINK_CFLAGS $CFLAGS"
AC_DEFINE([HAVE_METALINK], [1], [Define if using metalink.])
with_metalink=yes
], [
with_metalink=no
])
have_gpg=no
AS_IF([test x"$with_metalink" = xyes], [
dnl
dnl Check for GPGME
dnl
m4_ifdef([AM_PATH_GPGME], [
AM_PATH_GPGME([], [
LIBS="$GPGME_LIBS $LIBS"
CFLAGS="$GPGME_CFLAGS $CFLAGS"
AC_DEFINE([HAVE_GPGME], [1], [Define if GPGME is available.])
have_gpg=yes
])
])
])
])
dnl **********************************************************************
dnl Checks for IPv6
@@ -714,7 +745,8 @@ AS_IF([test "X$enable_pcre" != "Xno"],[
dnl Needed by src/Makefile.am
AM_CONDITIONAL([IRI_IS_ENABLED], [test "X$iri" != "Xno"])
AM_CONDITIONAL([WITH_SSL], [test "X$with_ssl" != "Xno"])
AM_CONDITIONAL([METALINK_IS_ENABLED], [test "X$with_metalink" != "Xno"])
dnl
dnl Create output
@@ -743,4 +775,6 @@ AC_MSG_NOTICE([Summary of build options:
Debugging: $ENABLE_DEBUG
Assertions: $ENABLE_ASSERTION
Valgrind: $VALGRIND_INFO
Metalink: $with_metalink
GPGME: $have_gpg
])

View File

@@ -2,28 +2,30 @@
#
# Do some checking before 'git push'.
CORES=`grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 0`
# Set a stricter bash mode
set -e
set -u
CORES=$(grep -c ^processor /proc/cpuinfo 2> /dev/null || echo 0)
if [ $CORES -lt 1 ]; then CORES=1; fi
make -f Makefile distclean 2>/dev/null
echo "Running: make distclean"
make distclean > /dev/null || true
# automatically exit on error
set -e
export CFLAGS="-std=c89 -pedantic -O2 -g -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wwrite-strings -Wshadow -Wformat -Wformat-security -Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition"
CFLAGS="-std=c89 -pedantic -O2 -g -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wwrite-strings -Wshadow -Wformat -Wformat-security -Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition"
CACHEFILE=$PWD/config_check.cache
# measure time consumed and print it at the end of the script
START=$(date +%s.%N)
echo "./bootstrap"
./bootstrap >/dev/null
echo "Running: ./bootstrap"
./bootstrap > /dev/null
echo
for CC in gcc clang; do
export CC
echo "*** checking CC=$CC"
echo "*** Testing with CC=$CC"
# the compiler changed, so we have to remove the cache file here
rm -f $CACHEFILE
@@ -31,20 +33,20 @@ for CC in gcc clang; do
for options in "" "--with-ssl=openssl"; do
export DISTCHECK_CONFIGURE_FLAGS="-C --cache-file=$CACHEFILE $options"
echo " ./configure $DISTCHECK_CONFIGURE_FLAGS"
./configure $DISTCHECK_CONFIGURE_FLAGS >/dev/null
./configure $DISTCHECK_CONFIGURE_FLAGS CFLAGS="$CFLAGS" > /dev/null
for xVALGRIND in 0 1; do
for xLCALL in C tr_TR.utf8; do
export TESTS_ENVIRONMENT="LC_ALL=$xLCALL VALGRIND_TESTS=$xVALGRIND"
echo " TESTS_ENVIRONMENT=\"$TESTS_ENVIRONMENT\"" make check -j$CORES
make check -j$CORES >/dev/null
make check -j$CORES > /dev/null
done
done
unset TESTS_ENVIRONMENT
export TESTS_ENVIRONMENT
echo " make distcheck -j$CORES"
make distcheck -j$CORES
echo " make distcheck CFLAGS=$CFLAGS -j$CORES"
make distcheck CFLAGS="$CFLAGS" -j$CORES > /dev/null
done
done

60
contrib/travis-ci Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/bash
# Set a stricter bash mode
set -e
set -u
# Set up the subset of tests this Matrix instance will run.
# One instance is forked for each of the SSL library possibilities
SSL=${1:-""}
case $SSL in
"") SSL_LIB="--without-ssl";;
"openssl") SSL_LIB="--with-ssl=openssl";;
"gnutls") SSL_LIB="--with-ssl=gnutls";;
esac
# For some reason. /proc/cpuinfo reports 16 cores on Travis, while the docs
# claim that each instance has only 2 cores. We believe the docs and force a
# value of n+1 here.
CORES=3
# Define a large number of Warning flags for the compiler. Hopefully, someone
# will sit and analyze the output to clean the warnings from the codebase.
CFLAGS="-std=c89 -pedantic -O2 -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wwrite-strings -Wshadow -Wformat -Wformat-security -Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition"
# A cachefile for ./configure. Saves significant time when reconfiguring
CACHEFILE=$PWD/config_check.cache
# measure time consumed and print it at the end of the script
START=$(date +%s)
# Test different Permutations of Wget. Always under Valgrind
#
# Options:
# - All Features Enabled
# - C [Default Locale]
# - Russian [Multibyte / Multicolumn Locale]
# - Turkish [Special Test due to issues with language]
# - IPv6 Disabled
# - C
for options in "" "--disable-ipv6"; do
export DISTCHECK_CONFIGURE_FLAGS="-C --cache-file=$CACHEFILE --enable-assert --enable-valgrind-tests $SSL_LIB $options"
echo " ./configure $DISTCHECK_CONFIGURE_FLAGS CFLAGS=\"$CFLAGS\""
./configure $DISTCHECK_CONFIGURE_FLAGS CFLAGS="$CFLAGS"
if [[ -z $options ]]; then
LANG_ARR=("ru_RU.UTF-8" "tr_TR.UTF-8" "C")
else
LANG_ARR=("C")
fi
for xLCALL in "${LANG_ARR[@]}"; do
export TESTS_ENVIRONMENT="LC_ALL=$xLCALL VALGRIND_TESTS=1"
echo " TESTS_ENVIRONMENT=\"$TESTS_ENVIRONMENT\" make distcheck CFLAGS=$CFLAGS -j$CORES"
make distcheck CFLAGS="$CFLAGS" -j$CORES
done
done
END=$(date +%s)
echo "Duration: $((END-START))"

View File

@@ -1,6 +1,6 @@
# Makefile for `wget' utility
# Copyright (C) 1995, 1996, 1997, 2007, 2008, 2009, 2010, 2011 Free
# Software Foundation, Inc.
# Copyright (C) 1995, 1996, 1997, 2007, 2008, 2009, 2010, 2011, 2015
# 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
@@ -57,7 +57,7 @@ wget.pod: $(srcdir)/wget.texi version.texi
$(TEXI2POD) -D VERSION="$(VERSION)" $(srcdir)/wget.texi $@
$(MAN): wget.pod
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" $? > $@
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" --utf8 $? > $@
#wget.cat: $(MAN)
# nroff -man $? > $@

View File

@@ -5,7 +5,8 @@
@c hence no sectioning command or @node.
@display
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008, 2015 Free Software
Foundation, Inc.
@uref{http://fsf.org/}
Everyone is permitted to copy and distribute verbatim copies

View File

@@ -1,7 +1,7 @@
#! /usr/bin/env perl
# Copyright (C) 1999, 2000, 2001, 2003, 2007, 2009, 2010, 2011 Free
# Software Foundation, Inc.
# Copyright (C) 1999, 2000, 2001, 2003, 2007, 2009, 2010, 2011, 2015
# Free Software Foundation, Inc.
# This file is part of GCC.
@@ -315,6 +315,8 @@ die "No filename or title\n" unless defined $fn && defined $tl;
$sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
print "=encoding utf-8\n\n";
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT EXITSTATUS
FILES BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
if(exists $sects{$sect}) {

View File

@@ -2,6 +2,7 @@
@c %**start of header
@setfilename wget.info
@documentencoding UTF-8
@include version.texi
@settitle GNU Wget @value{VERSION} Manual
@c Disable the monstrous rectangles beside overfull hbox-es.
@@ -31,8 +32,8 @@ data.
@c man begin COPYRIGHT
Copyright @copyright{} 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
@iftex
Permission is granted to make and distribute verbatim copies of
@@ -59,11 +60,11 @@ Texts. A copy of the license is included in the section entitled
@title GNU Wget @value{VERSION}
@subtitle The non-interactive download utility
@subtitle Updated for Wget @value{VERSION}, @value{UPDATED}
@author by Hrvoje Nik@v{s}i@'{c} and others
@author by Hrvoje Nikšić and others
@ignore
@c man begin AUTHOR
Originally written by Hrvoje Niksic <hniksic@xemacs.org>.
Originally written by Hrvoje Nikšić <hniksic@xemacs.org>.
@c man end
@c man begin SEEALSO
This is @strong{not} the complete manual for GNU Wget.
@@ -506,6 +507,23 @@ treated as @samp{html} if the Content-Type matches @samp{text/html}.
Furthermore, the @var{file}'s location will be implicitly used as base
href if none was specified.
@cindex input-metalink
@item --input-metalink=@var{file}
Downloads files covered in local Metalink @var{file}. Metalink version 3
and 4 are supported.
@cindex metalink-over-http
@item --metalink-over-http
Issues HTTP HEAD request instead of GET and extracts Metalink metadata
from response headers. Then it switches to Metalink download.
If no valid Metalink metadata is found, it falls back to ordinary HTTP download.
@cindex preferred-location
@item --preferred-location
Set preferred location for Metalink resources. This has effect if multiple
resources with same priority are available.
@cindex force html
@item -F
@itemx --force-html
@@ -533,6 +551,11 @@ would be resolved to @samp{http://foo/baz/b.html}.
@cindex specify config
@item --config=@var{FILE}
Specify the location of a startup file you wish to use.
@item --rejected-log=@var{logfile}
Logs all URL rejections to @var{logfile} as comma separated values. The values
include the reason of rejection, the URL and the parent URL it was found in.
@end table
@node Download Options, Directory Options, Logging and Input File Options, Invoking
@@ -585,6 +608,9 @@ content will be placed in @var{file}. This was disabled in version
1.11, but has been reinstated (with a warning) in 1.11.2, as there are
some cases where this behavior can actually have some use.
A combination with @samp{-nc} is only accepted if the given output
file does not exist.
Note that a combination with @samp{-k} is only permitted when
downloading a single document, as in that case it will just convert
all relative URIs to external ones; @samp{-k} makes no sense for
@@ -626,6 +652,9 @@ of a file depends on the local and remote timestamp and size of the
file (@pxref{Time-Stamping}). @samp{-nc} may not be specified at the
same time as @samp{-N}.
A combination with @samp{-O}/@samp{--output-document} is only accepted
if the given output file does not exist.
Note that when @samp{-nc} is specified, files with the suffixes
@samp{.html} or @samp{.htm} will be loaded from the local disk and
parsed as if they had been retrieved from the Web.
@@ -787,6 +816,10 @@ used alongside the @samp{--logfile} option.
@itemx --timestamping
Turn on time-stamping. @xref{Time-Stamping}, for details.
@item --no-if-modified-since
Do not send If-Modified-Since header in @samp{-N} mode. Send preliminary HEAD
request instead. This has only effect in @samp{-N} mode.
@item --no-use-server-timestamps
Don't set the local file's timestamp by the one on the server.
@@ -1521,6 +1554,11 @@ Please note that wget does not require the content to be of the form
simply transmit whatever data is provided to it. Most servers however expect
the POST data to be in the above format when processing HTML Forms.
When sending a POST request using the @samp{--post-file} option, Wget treats
the file as a binary file and will send every character in the POST request
without stripping trailing newline or formfeed characters. Any other control
characters in the text will also be sent as-is in the POST request.
Please be aware that Wget needs to know the size of the POST data in
advance. Therefore the argument to @code{--post-file} must be a regular
file; specifying a FIFO or something like @file{/dev/stdin} won't work.
@@ -1637,8 +1675,9 @@ form-based authentication.
@cindex SSL
To support encrypted HTTP (HTTPS) downloads, Wget must be compiled
with an external SSL library, currently OpenSSL. If Wget is compiled
without SSL support, none of these options are available.
with an external SSL library. The current default is GnuTLS.
In addition, Wget also supports HSTS (HTTP Strict Transport Security).
If Wget is compiled without SSL support, none of these options are available.
@table @samp
@cindex SSL protocol, choose
@@ -1686,6 +1725,12 @@ this option to bypass the verification and proceed with the download.
site's authenticity, or if you really don't care about the validity of
its certificate.} It is almost always a bad idea not to check the
certificates when transmitting confidential or important data.
For self-signed/internal certificates, you should download the certificate
and verify against that instead of forcing this insecure mode.
If you are really sure of not desiring any certificate verification, you
can specify --check-certificate=quiet to tell wget to not print any
warning about invalid certificates, albeit in most cases this is the
wrong thing to do.
@cindex SSL certificate
@item --certificate=@var{file}
@@ -1768,6 +1813,71 @@ read random data from EGD socket specified using this option.
If this option is not specified (and the equivalent startup command is
not used), EGD is never contacted. EGD is not needed on modern Unix
systems that support @file{/dev/urandom}.
@cindex HSTS
@item --no-hsts
Wget supports HSTS (HTTP Strict Transport Security, RFC 6797) by default.
Use @samp{--no-hsts} to make Wget act as a non-HSTS-compliant UA. As a
consequence, Wget would ignore all the @code{Strict-Transport-Security}
headers, and would not enforce any existing HSTS policy.
@item --hsts-file=@var{file}
By default, Wget stores its HSTS database in @file{~/.wget-hsts}.
You can use @samp{--hsts-file} to override this. Wget will use
the supplied file as the HSTS database. Such file must conform to the
correct HSTS database format used by Wget. If Wget cannot parse the provided
file, the behaviour is unspecified.
The Wget's HSTS database is a plain text file. Each line contains an HSTS entry
(ie. a site that has issued a @code{Strict-Transport-Security} header and that
therefore has specified a concrete HSTS policy to be applied). Lines starting with
a dash (@code{#}) are ignored by Wget. Please note that in spite of this convenient
human-readability hand-hacking the HSTS database is generally not a good idea.
An HSTS entry line consists of several fields separated by one or more whitespace:
@code{<hostname> SP [<port>] SP <include subdomains> SP <created> SP <max-age>}
The @var{hostname} and @var{port} fields indicate the hostname and port to which
the given HSTS policy applies. The @var{port} field may be zero, and it will, in
most of the cases. That means that the port number will not be taken into account
when deciding whether such HSTS policy should be applied on a given request (only
the hostname will be evaluated). When @var{port} is different to zero, both the
target hostname and the port will be evaluated and the HSTS policy will only be applied
if both of them match. This feature has been included for testing/development purposes only.
The Wget testsuite (in @file{testenv/}) creates HSTS databases with explicit ports
with the purpose of ensuring Wget's correct behaviour. Applying HSTS policies to ports
other than the default ones is discouraged by RFC 6797 (see Appendix B "Differences
between HSTS Policy and Same-Origin Policy"). Thus, this functionality should not be used
in production environments and @var{port} will typically be zero. The last three fields
do what they are expected to. The field @var{include_subdomains} can either be @code{1}
or @code{0} and it signals whether the subdomains of the target domain should be
part of the given HSTS policy as well. The @var{created} and @var{max-age} fields
hold the timestamp values of when such entry was created (first seen by Wget) and the
HSTS-defined value 'max-age', which states how long should that HSTS policy remain active,
measured in seconds elapsed since the timestamp stored in @var{created}. Once that time
has passed, that HSTS policy will no longer be valid and will eventually be removed
from the database.
If you supply your own HSTS database via @samp{--hsts-file}, be aware that Wget
may modify the provided file if any change occurs between the HSTS policies
requested by the remote servers and those in the file. When Wget exists,
it effectively updates the HSTS database by rewriting the database file with the new entries.
If the supplied file does not exist, Wget will create one. This file will contain the new HSTS
entries. If no HSTS entries were generated (no @code{Strict-Transport-Security} headers
were sent by any of the servers) then no file will be created, not even an empty one. This
behaviour applies to the default database file (@file{~/.wget-hsts}) as well: it will not be
created until some server enforces an HSTS policy.
Care is taken not to override possible changes made by other Wget processes at
the same time over the HSTS database. Before dumping the updated HSTS entries
on the file, Wget will re-read it and merge the changes.
Using a custom HSTS database and/or modifying an existing one is discouraged.
For more information about the potential security threats arised from such practice,
see section 14 "Security Considerations" of RFC 6797, specially section 14.9
"Creative Manipulation of HSTS Policy Store".
@end table
@cindex WARC
@@ -1910,6 +2020,43 @@ this option has no effect. Symbolic links are always traversed in this
case.
@end table
@section FTPS Options
@table @samp
@item --ftps-implicit
This option tells Wget to use FTPS implicitly. Implicit FTPS consists of initializing
SSL/TLS from the very beginning of the control connection. This option does not send
an @code{AUTH TLS} command: it assumes the server speaks FTPS and directly starts an
SSL/TLS connection. If the attempt is successful, the session continues just like
regular FTPS (@code{PBSZ} and @code{PROT} are sent, etc.).
Implicit FTPS is no longer a requirement for FTPS implementations, and thus
many servers may not support it. If @samp{--ftps-implicit} is passed and no explicit
port number specified, the default port for implicit FTPS, 990, will be used, instead
of the default port for the "normal" (explicit) FTPS which is the same as that of FTP,
21.
@item --no-ftps-resume-ssl
Do not resume the SSL/TLS session in the data channel. When starting a data connection,
Wget tries to resume the SSL/TLS session previously started in the control connection.
SSL/TLS session resumption avoids performing an entirely new handshake by reusing
the SSL/TLS parameters of a previous session. Typically, the FTPS servers want it that way,
so Wget does this by default. Under rare circumstances however, one might want to
start an entirely new SSL/TLS session in every data connection.
This is what @samp{--no-ftps-resume-ssl} is for.
@item --ftps-clear-data-connection
All the data connections will be in plain text. Only the control connection will be
under SSL/TLS. Wget will send a @code{PROT C} command to achieve this, which must be
approved by the server.
@item --ftps-fallback-to-ftp
Fall back to FTP if FTPS is not supported by the target server. For security reasons,
this option is not asserted by default. The default behaviour is to exit with an error.
If a server does not successfully reply to the initial @code{AUTH TLS} command, or in the
case of implicit FTPS, if the initial SSL/TLS connection attempt is rejected, it is
considered that such server does not support FTPS.
@end table
@node Recursive Retrieval Options, Recursive Accept/Reject Options, FTP Options, Invoking
@section Recursive Retrieval Options
@@ -1988,6 +2135,23 @@ Note that only at the end of the download can Wget know which links have
been downloaded. Because of that, the work done by @samp{-k} will be
performed at the end of all the downloads.
@item --convert-file-only
This option converts only the filename part of the URLs, leaving the rest
of the URLs untouched. This filename part is sometimes referred to as the
"basename", although we avoid that term here in order not to cause confusion.
It works particularly well in conjunction with @samp{--adjust-extension}, although
this coupling is not enforced. It proves useful to populate Internet caches
with files downloaded from different hosts.
Example: if some link points to @file{//foo.com/bar.cgi?xyz} with
@samp{--adjust-extension} asserted and its local destination is intended to be
@file{./foo.com/bar.cgi?xyz.css}, then the link would be converted to
@file{//foo.com/bar.cgi?xyz.css}. Note that only the filename part has been
modified. The rest of the URL has been left untouched, including the net path
(@code{//}) which would otherwise be processed by Wget and converted to the
effective scheme (ie. @code{http://}).
@cindex backing up converted files
@item -K
@itemx --backup-converted
@@ -4096,12 +4260,7 @@ me).
@section Contributors
@cindex contributors
@iftex
GNU Wget was written by Hrvoje Nik@v{s}i@'{c} @email{hniksic@@xemacs.org},
@end iftex
@ifnottex
GNU Wget was written by Hrvoje Niksic @email{hniksic@@xemacs.org}.
@end ifnottex
GNU Wget was written by Hrvoje Nikšić @email{hniksic@@xemacs.org},
However, the development of Wget could never have gone as far as it has, were
it not for the help of many people, either with bug reports, feature proposals,
@@ -4141,14 +4300,8 @@ portability fixes.
Gordon Matzigkeit---@file{.netrc} support.
@item
@iftex
Zlatko @v{C}alu@v{s}i@'{c}, Tomislav Vujec and Dra@v{z}en
Ka@v{c}ar---feature suggestions and ``philosophical'' discussions.
@end iftex
@ifnottex
Zlatko Calusic, Tomislav Vujec and Drazen Kacar---feature suggestions
and ``philosophical'' discussions.
@end ifnottex
Zlatko Čalušić, Tomislav Vujec and Dražen
Kačar---feature suggestions and ``philosophical'' discussions.
@item
Darko Budor---initial port to Windows.
@@ -4158,21 +4311,11 @@ Antonio Rosella---help and suggestions, plus the initial Italian
translation.
@item
@iftex
Tomislav Petrovi@'{c}, Mario Miko@v{c}evi@'{c}---many bug reports and
Tomislav Petrović, Mario Mikočević---many bug reports and
suggestions.
@end iftex
@ifnottex
Tomislav Petrovic, Mario Mikocevic---many bug reports and suggestions.
@end ifnottex
@item
@iftex
Fran@,{c}ois Pinard---many thorough bug reports and discussions.
@end iftex
@ifnottex
Francois Pinard---many thorough bug reports and discussions.
@end ifnottex
François Pinard---many thorough bug reports and discussions.
@item
Karl Eichwalder---lots of help with internationalization, Makefile
@@ -4235,12 +4378,7 @@ Wanderlei Cavassin,
Gilles Cedoc,
Tim Charron,
Noel Cragg,
@iftex
Kristijan @v{C}onka@v{s},
@end iftex
@ifnottex
Kristijan Conkas,
@end ifnottex
Kristijan Čonkaš,
John Daily,
Andreas Damm,
Ahmon Dancy,
@@ -4250,27 +4388,12 @@ Alexander Dergachev,
Andrew Deryabin,
Ulrich Drepper,
Marc Duponcheel,
@iftex
Damir D@v{z}eko,
@end iftex
@ifnottex
Damir Dzeko,
@end ifnottex
Damir Džeko,
Alan Eldridge,
Hans-Andreas Engel,
@iftex
Aleksandar Erkalovi@'{c},
@end iftex
@ifnottex
Aleksandar Erkalovic,
@end ifnottex
Aleksandar Erkalović,
Andy Eskilsson,
@iftex
Jo@~{a}o Ferreira,
@end iftex
@ifnottex
Joao Ferreira,
@end ifnottex
João Ferreira,
Christian Fraenkel,
David Fritz,
Mike Frysinger,
@@ -4295,25 +4418,10 @@ Richard Huveneers,
Jonas Jensen,
Larry Jones,
Simon Josefsson,
@iftex
Mario Juri@'{c},
@end iftex
@ifnottex
Mario Juric,
@end ifnottex
@iftex
Hack Kampbj@o rn,
@end iftex
@ifnottex
Hack Kampbjorn,
@end ifnottex
Mario Jurić,
Hack Kampbjørn,
Const Kaplinsky,
@iftex
Goran Kezunovi@'{c},
@end iftex
@ifnottex
Goran Kezunovic,
@end ifnottex
Goran Kezunović,
Igor Khristophorov,
Robert Kleine,
KOJIMA Haime,
@@ -4322,31 +4430,14 @@ Alexander Kourakos,
Martin Kraemer,
Sami Krank,
Jay Krell,
@tex
$\Sigma\acute{\iota}\mu o\varsigma\;
\Xi\varepsilon\nu\iota\tau\acute{\epsilon}\lambda\lambda\eta\varsigma$
(Simos KSenitellis),
@end tex
@ifnottex
Simos KSenitellis,
@end ifnottex
Σίμος Ξενιτέλλης (Simos KSenitellis),
Christian Lackas,
Hrvoje Lacko,
Daniel S.@: Lewart,
@iftex
Nicol@'{a}s Lichtmeier,
@end iftex
@ifnottex
Nicolas Lichtmeier,
@end ifnottex
Nicolás Lichtmeier,
Dave Love,
Alexander V.@: Lukyanov,
@iftex
Thomas Lu@ss{}nig,
@end iftex
@ifnottex
Thomas Lussnig,
@end ifnottex
Thomas Lußnig,
Andre Majorel,
Aurelien Marchand,
Matthew J.@: Mellon,
@@ -4367,31 +4458,15 @@ Leonid Petrov,
Simone Piunno,
Andrew Pollock,
Steve Pothier,
@iftex
Jan P@v{r}ikryl,
@end iftex
@ifnottex
Jan Prikryl,
@end ifnottex
Jan Přikryl,
Marin Purgar,
@iftex
Csaba R@'{a}duly,
@end iftex
@ifnottex
Csaba Raduly,
@end ifnottex
Csaba Ráduly,
Keith Refson,
Bill Richardson,
Tyler Riddle,
Tobias Ringstrom,
Jochen Roderburg,
@c Texinfo doesn't grok @'{@i}, so we have to use TeX itself.
@tex
Juan Jos\'{e} Rodr\'{\i}guez,
@end tex
@ifnottex
Juan Jose Rodriguez,
@end ifnottex
Juan José Rodríguez,
Maciej W.@: Rozycki,
Edward J.@: Sabol,
Heinz Salzmann,
@@ -4418,12 +4493,7 @@ Dave Turner,
Gisle Vanem,
Rabin Vincent,
Russell Vincent,
@iftex
@v{Z}eljko Vrba,
@end iftex
@ifnottex
Zeljko Vrba,
@end ifnottex
Željko Vrba,
Charles G Waldman,
Douglas E.@: Wegscheid,
Ralf Wildenhues,
@@ -4432,12 +4502,7 @@ Benjamin Wolsey,
Saint Xavier,
YAMAZAKI Makoto,
Jasmin Zainul,
@iftex
Bojan @v{Z}drnja,
@end iftex
@ifnottex
Bojan Zdrnja,
@end ifnottex
Bojan Ždrnja,
Kristijan Zimmer,
Xin Zou.

2
gnulib

Submodule gnulib updated: ecc5d3e148...55c6f22b80

View File

@@ -1,6 +1,6 @@
/* Configuration header file for MS-DOS/Watt-32
Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
Copyright (C) 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* MSDOS utility functions.
Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -26,6 +26,7 @@ src/init.c
src/iri.c
src/log.c
src/main.c
src/metalink.c
src/mswindows.c
src/netrc.c
src/openssl.c

View File

@@ -1,6 +1,6 @@
# Makefile for `wget' utility
# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
# 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
# Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,10 @@ if IRI_IS_ENABLED
IRI_OBJ = iri.c
endif
if METALINK_IS_ENABLED
METALINK_OBJ = metalink.c
endif
# The following line is losing on some versions of make!
DEFS = @DEFS@ -DSYSTEM_WGETRC=\"$(sysconfdir)/wgetrc\" -DLOCALEDIR=\"$(localedir)\"
LIBS = @LIBICONV@ @LIBINTL@ @LIBS@ $(LIB_CLOCK_GETTIME)
@@ -44,16 +48,16 @@ EXTRA_DIST = css.l css.c css_.c build_info.c.in
bin_PROGRAMS = wget
wget_SOURCES = connect.c convert.c cookies.c ftp.c \
css_.c css-url.c \
ftp-basic.c ftp-ls.c hash.c host.c html-parse.c html-url.c \
ftp-basic.c ftp-ls.c hash.c host.c hsts.c html-parse.c html-url.c \
http.c init.c log.c main.c netrc.c progress.c ptimer.c \
recur.c res.c retr.c spider.c url.c warc.c \
utils.c exits.c build_info.c $(IRI_OBJ) \
utils.c exits.c build_info.c $(IRI_OBJ) $(METALINK_OBJ) \
css-url.h css-tokens.h connect.h convert.h cookies.h \
ftp.h hash.h host.h html-parse.h html-url.h \
ftp.h hash.h host.h hsts.h html-parse.h html-url.h \
http.h http-ntlm.h init.h log.h mswindows.h netrc.h \
options.h progress.h ptimer.h recur.h res.h retr.h \
spider.h ssl.h sysdep.h url.h warc.h utils.h wget.h iri.h \
exits.h version.h
exits.h version.h metalink.h
nodist_wget_SOURCES = version.c
EXTRA_wget_SOURCES = iri.c
LDADD = $(LIBOBJS) ../lib/libgnu.a

View File

@@ -9,6 +9,9 @@ ntlm defined ENABLE_NTLM
opie defined ENABLE_OPIE
psl defined HAVE_LIBPSL
metalink defined HAVE_METALINK
gpgme defined HAVE_GPGME
ssl choice:
openssl defined HAVE_LIBSSL || defined HAVE_LIBSSL32
gnutls defined HAVE_LIBGNUTLS

View File

@@ -1,6 +1,6 @@
/* Establishing and handling network connections.
Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Declarations for connect.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Conversion of links to local files.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014
Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
2014, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
@@ -46,6 +46,7 @@ as that of the covered work. */
#include "html-url.h"
#include "css-url.h"
#include "iri.h"
#include "xstrndup.h"
static struct hash_table *dl_file_url_map;
struct hash_table *dl_url_file_map;
@@ -136,8 +137,9 @@ convert_links_in_hashtable (struct hash_table *downloaded_set,
form. We do this even if the URL already is in
relative form, because our directory structure may
not be identical to that on the server (think `-nd',
`--cut-dirs', etc.) */
cur_url->convert = CO_CONVERT_TO_RELATIVE;
`--cut-dirs', etc.). If --convert-file-only was passed,
we only convert the basename portion of the URL. */
cur_url->convert = (opt.convert_file_only ? CO_CONVERT_BASENAME_ONLY : CO_CONVERT_TO_RELATIVE);
cur_url->local_name = xstrdup (local_name);
DEBUGP (("will convert url %s to local %s\n", u->url, local_name));
}
@@ -193,7 +195,7 @@ convert_all_links (void)
convert_links_in_hashtable (downloaded_css_set, 1, &file_count);
secs = ptimer_measure (timer);
logprintf (LOG_VERBOSE, _("Converted %d files in %s seconds.\n"),
logprintf (LOG_VERBOSE, _("Converted links in %d files in %s seconds.\n"),
file_count, print_decimal (secs));
ptimer_destroy (timer);
@@ -206,6 +208,7 @@ static const char *replace_attr_refresh_hack (const char *, int, FILE *,
const char *, int);
static char *local_quote_string (const char *, bool);
static char *construct_relative (const char *, const char *);
static char *convert_basename (const char *, const struct urlpos *);
/* Change the links in one file. LINKS is a list of links in the
document, along with their positions and the desired direction of
@@ -221,7 +224,7 @@ convert_links (const char *file, struct urlpos *links)
struct urlpos *link;
int to_url_count = 0, to_file_count = 0;
logprintf (LOG_VERBOSE, _("Converting %s... "), file);
logprintf (LOG_VERBOSE, _("Converting links in %s... "), file);
{
/* First we do a "dry run": go through the list L and see whether
@@ -315,9 +318,32 @@ convert_links (const char *file, struct urlpos *links)
DEBUGP (("TO_RELATIVE: %s to %s at position %d in %s.\n",
link->url->url, newname, link->pos, file));
xfree (newname);
xfree (quoted_newname);
++to_file_count;
break;
}
case CO_CONVERT_BASENAME_ONLY:
{
char *newname = convert_basename (p, link);
char *quoted_newname = local_quote_string (newname, link->link_css_p);
if (link->link_css_p)
p = replace_plain (p, link->size, fp, quoted_newname);
else if (!link->link_refresh_p)
p = replace_attr (p, link->size, fp, quoted_newname);
else
p = replace_attr_refresh_hack (p, link->size, fp, quoted_newname,
link->refresh_timeout);
DEBUGP (("Converted file part only: %s to %s at position %d in %s.\n",
link->url->url, newname, link->pos, file));
xfree (newname);
xfree (quoted_newname);
++to_file_count;
break;
}
case CO_CONVERT_TO_COMPLETE:
@@ -336,6 +362,7 @@ convert_links (const char *file, struct urlpos *links)
DEBUGP (("TO_COMPLETE: <something> to %s at position %d in %s.\n",
newlink, link->pos, file));
xfree (quoted_newlink);
++to_url_count;
break;
@@ -414,14 +441,89 @@ construct_relative (const char *basefile, const char *linkfile)
++basedirs;
}
/* Construct LINK as explained above. */
link = xmalloc (3 * basedirs + strlen (linkfile) + 1);
for (i = 0; i < basedirs; i++)
memcpy (link + 3 * i, "../", 3);
strcpy (link + 3 * i, linkfile);
if (!basedirs && (b = strpbrk (linkfile, "/:")) && *b == ':')
{
link = xmalloc (2 + strlen (linkfile) + 1);
memcpy (link, "./", 2);
strcpy (link + 2, linkfile);
}
else
{
/* Construct LINK as explained above. */
link = xmalloc (3 * basedirs + strlen (linkfile) + 1);
for (i = 0; i < basedirs; i++)
memcpy (link + 3 * i, "../", 3);
strcpy (link + 3 * i, linkfile);
}
return link;
}
/* Construct and return a "transparent proxy" URL
reflecting changes made by --adjust-extension to the file component
(i.e., "basename") of the original URL, but leaving the "dirname"
of the URL (protocol://hostname... portion) untouched.
Think: populating a squid cache via a recursive wget scrape, where
changing URLs to work locally with "file://..." is NOT desirable.
Example:
if
p = "//foo.com/bar.cgi?xyz"
and
link->local_name = "docroot/foo.com/bar.cgi?xyz.css"
then
new_construct_func(p, link);
will return
"//foo.com/bar.cgi?xyz.css"
Essentially, we do s/$(basename orig_url)/$(basename link->local_name)/
*/
static char *
convert_basename (const char *p, const struct urlpos *link)
{
int len = link->size;
char *url = NULL;
char *org_basename = NULL, *local_basename = NULL;
char *result = NULL;
if (*p == '"' || *p == '\'')
{
len -= 2;
p++;
}
url = xstrndup (p, len);
org_basename = strrchr (url, '/');
if (org_basename)
org_basename++;
else
org_basename = url;
local_basename = strrchr (link->local_name, '/');
if (local_basename)
local_basename++;
else
local_basename = url;
/*
* If the basenames differ, graft the adjusted basename (local_basename)
* onto the original URL.
*/
if (strcmp (org_basename, local_basename) == 0)
result = url;
else
{
result = uri_merge (url, local_basename);
xfree (url);
}
return result;
}
/* Used by write_backup_file to remember which files have been
written. */
static struct hash_table *converted_files;

View File

@@ -1,6 +1,6 @@
/* Declarations for convert.c
Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -40,6 +40,8 @@ enum convert_options {
CO_NOCONVERT = 0, /* don't convert this URL */
CO_CONVERT_TO_RELATIVE, /* convert to relative, e.g. to
"../../otherdir/foo.gif" */
CO_CONVERT_BASENAME_ONLY, /* convert the file portion only (basename)
leaving the rest of the URL unchanged */
CO_CONVERT_TO_COMPLETE, /* convert to absolute, e.g. to
"http://orighost/somedir/bar.jpg". */
CO_NULLIFY_BASE /* change to empty string. */

View File

@@ -1,6 +1,6 @@
/* Support for cookies.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011 Free Software Foundation, Inc.
2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Support for cookies.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011 Free Software Foundation, Inc.
2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,6 @@
/* Declarations for css.lex
Copyright (C) 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2006, 2009, 2010, 2011, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Collect URLs from CSS source.
Copyright (C) 1998, 2000, 2001, 2002, 2003, 2009, 2010, 2011, 2014 Free
Software Foundation, Inc.
Copyright (C) 1998, 2000, 2001, 2002, 2003, 2009, 2010, 2011, 2014,
2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,6 @@
/* Declarations for css-url.c.
Copyright (C) 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2006, 2009, 2010, 2011, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.

View File

@@ -6,7 +6,8 @@
%{
/* Lex source for CSS tokenizing.
Taken from http://www.w3.org/TR/CSS21/grammar.html#q2
Copyright (C) 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2006, 2009, 2010, 2011, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,6 @@
/* Exit status handling.
Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Copyright (C) 2009, 2010, 2011, 2012, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,6 @@
/* Exit status related declarations.
Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
Copyright (C) 2009, 2010, 2011, 2012, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Basic FTP routines.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -135,6 +135,23 @@ ftp_request (const char *command, const char *value)
return res;
}
uerr_t
ftp_greeting (int csock)
{
uerr_t err = FTPOK;
char *response = NULL;
err = ftp_response (csock, &response);
if (err != FTPOK)
goto bail;
if (*response != '2')
err = FTPSRVERR;
bail:
if (response)
xfree (response);
return err;
}
/* Sends the USER and PASS commands to the server, to control
connection socket csock. */
uerr_t
@@ -144,16 +161,6 @@ ftp_login (int csock, const char *acc, const char *pass)
char *request, *respline;
int nwritten;
/* Get greeting. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
return err;
if (*respline != '2')
{
xfree (respline);
return FTPSRVERR;
}
xfree (respline);
/* Send USER username. */
request = ftp_request ("USER", acc);
nwritten = fd_write (csock, request, strlen (request), -1);
@@ -481,6 +488,119 @@ ftp_eprt (int csock, int *local_sock)
}
#endif
#ifdef HAVE_SSL
/*
* The following three functions defined into this #ifdef block
* wrap the extended FTP commands defined in RFC 2228 (FTP Security Extensions).
* Currently, only FTPS is supported, so these functions are only compiled when SSL
* support is available, because there's no point in using FTPS when there's no SSL.
* Shall someone add new secure FTP protocols in the future, feel free to remove this
* #ifdef, or add new constants to it.
*/
/*
* Sends an AUTH command as defined by RFC 2228,
* deriving its argument from the scheme. For example, if the provided scheme
* is SCHEME_FTPS, the command sent will be "AUTH TLS". Currently, this is the only
* scheme supported, so this function will return FTPNOAUTH when supplied a different
* one. It will also return FTPNOAUTH if the target server does not support FTPS.
*/
uerr_t
ftp_auth (int csock, enum url_scheme scheme)
{
uerr_t err = 0;
int written = 0;
char *request = NULL, *response = NULL;
if (scheme == SCHEME_FTPS)
{
request = ftp_request ("AUTH", "TLS");
written = fd_write (csock, request, strlen (request), -1);
if (written < 0)
{
err = WRITEFAILED;
goto bail;
}
err = ftp_response (csock, &response);
if (err != FTPOK)
goto bail;
if (*response != '2')
err = FTPNOAUTH;
}
else
err = FTPNOAUTH;
bail:
xfree (request);
xfree (response);
return err;
}
uerr_t
ftp_pbsz (int csock, int pbsz)
{
uerr_t err = 0;
int written = 0;
char spbsz[5];
char *request = NULL, *response = NULL;
snprintf (spbsz, 5, "%d", pbsz);
request = ftp_request ("PBSZ", spbsz);
written = fd_write (csock, request, strlen (request), -1);
if (written < 0)
{
err = WRITEFAILED;
goto bail;
}
err = ftp_response (csock, &response);
if (err != FTPOK)
goto bail;
if (*response != '2')
err = FTPNOPBSZ;
bail:
xfree (request);
xfree (response);
return err;
}
uerr_t
ftp_prot (int csock, enum prot_level prot)
{
uerr_t err = 0;
int written = 0;
char *request = NULL, *response = NULL;
/* value must be a single character value */
char value[2];
value[0] = prot;
value[1] = '\0';
request = ftp_request ("PROT", value);
written = fd_write (csock, request, strlen (request), -1);
if (written < 0)
{
err = WRITEFAILED;
goto bail;
}
err = ftp_response (csock, &response);
if (err != FTPOK)
goto bail;
if (*response != '2')
err = FTPNOPROT;
bail:
xfree (request);
xfree (response);
return err;
}
#endif /* HAVE_SSL */
/* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
transfer. Reads the response from server and parses it. Reads the
host and port addresses and returns them. */

View File

@@ -1,7 +1,7 @@
/* Parsing FTP `ls' output.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Opie (s/key) support for FTP.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

306
src/ftp.c
View File

@@ -1,7 +1,7 @@
/* File Transfer Protocol support.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -44,6 +44,7 @@ as that of the covered work. */
#include "url.h"
#include "retr.h"
#include "ftp.h"
#include "ssl.h"
#include "connect.h"
#include "host.h"
#include "netrc.h"
@@ -237,6 +238,78 @@ print_length (wgint size, wgint start, bool authoritative)
static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **);
static uerr_t
get_ftp_greeting(int csock, ccon *con)
{
uerr_t err = 0;
/* Get the server's greeting */
err = ftp_greeting (csock);
if (err != FTPOK)
{
logputs (LOG_NOTQUIET, "Error in server response. Closing.\n");
fd_close (csock);
con->csock = -1;
}
return err;
}
#ifdef HAVE_SSL
static uerr_t
init_control_ssl_connection (int csock, struct url *u, bool *using_control_security)
{
bool using_security = false;
/* If '--ftps-implicit' was passed, perform the SSL handshake directly,
* and do not send an AUTH command.
* Otherwise send an AUTH sequence before login,
* and perform the SSL handshake if accepted by server.
*/
if (!opt.ftps_implicit && !opt.server_response)
logputs (LOG_VERBOSE, "==> AUTH TLS ... ");
if (opt.ftps_implicit || ftp_auth (csock, SCHEME_FTPS) == FTPOK)
{
if (!ssl_connect_wget (csock, u->host, NULL))
{
fd_close (csock);
return CONSSLERR;
}
else if (!ssl_check_certificate (csock, u->host))
{
fd_close (csock);
return VERIFCERTERR;
}
if (!opt.ftps_implicit && !opt.server_response)
logputs (LOG_VERBOSE, " done.\n");
/* If implicit FTPS was requested, we act as "normal" FTP, but over SSL.
* We're not using RFC 2228 commands.
*/
using_security = true;
}
else
{
/* The server does not support 'AUTH TLS'.
* Check if --ftps-fallback-to-ftp was passed. */
if (opt.ftps_fallback_to_ftp)
{
logputs (LOG_NOTQUIET, "Server does not support AUTH TLS. Falling back to FTP.\n");
using_security = false;
}
else
{
fd_close (csock);
return FTPNOAUTH;
}
}
*using_control_security = using_security;
return NOCONERROR;
}
#endif
/* Retrieves a file with denoted parameters through opening an FTP
connection to the server. It always closes the data connection,
and closes the control connection in case of error. If warc_tmp
@@ -248,11 +321,11 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
{
int csock, dtsock, local_sock, res;
uerr_t err = RETROK; /* appease the compiler */
FILE *fp;
FILE *fp = NULL;
struct_fstat st;
char *respline, *tms;
const char *user, *passwd, *tmrate;
int cmd = con->cmd;
bool pasv_mode_open = false;
wgint expected_bytes = 0;
bool got_expected_bytes = false;
bool rest_failed = false;
@@ -261,6 +334,15 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
char type_char;
bool try_again;
bool list_a_used = false;
#ifdef HAVE_SSL
enum prot_level prot = (opt.ftps_clear_data_connection ? PROT_CLEAR : PROT_PRIVATE);
/* these variables tell whether the target server
* accepts the security extensions (RFC 2228) or not,
* and whether we're actually using any of them
* (encryption at the control connection only,
* or both at control and data connections) */
bool using_control_security = false, using_data_security = false;
#endif
assert (con != NULL);
assert (con->target != NULL);
@@ -286,8 +368,36 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
local_sock = -1;
con->dltime = 0;
#ifdef HAVE_SSL
if (u->scheme == SCHEME_FTPS)
{
/* Initialize SSL layer first */
if (!ssl_init ())
{
scheme_disable (SCHEME_FTPS);
logprintf (LOG_NOTQUIET, _("Could not initialize SSL. It will be disabled."));
err = SSLINITFAILED;
return err;
}
/* If we're using the default FTP port and implicit FTPS was requested,
* rewrite the port to the default *implicit* FTPS port.
*/
if (opt.ftps_implicit && u->port == DEFAULT_FTP_PORT)
{
DEBUGP (("Implicit FTPS was specified. Rewriting default port to %d.\n", DEFAULT_FTPS_IMPLICIT_PORT));
u->port = DEFAULT_FTPS_IMPLICIT_PORT;
}
}
#endif
if (!(cmd & DO_LOGIN))
csock = con->csock;
{
csock = con->csock;
#ifdef HAVE_SSL
using_data_security = con->st & DATA_CHANNEL_SECURITY;
#endif
}
else /* cmd & DO_LOGIN */
{
char *host = con->proxy ? con->proxy->host : u->host;
@@ -309,6 +419,43 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
else
con->csock = -1;
#ifdef HAVE_SSL
if (u->scheme == SCHEME_FTPS)
{
/* If we're in implicit FTPS mode, we have to set up SSL/TLS before everything else.
* Otherwise we first read the server's greeting, and then send an "AUTH TLS".
*/
if (opt.ftps_implicit)
{
err = init_control_ssl_connection (csock, u, &using_control_security);
if (err != NOCONERROR)
return err;
err = get_ftp_greeting (csock, con);
if (err != FTPOK)
return err;
}
else
{
err = get_ftp_greeting (csock, con);
if (err != FTPOK)
return err;
err = init_control_ssl_connection (csock, u, &using_control_security);
if (err != NOCONERROR)
return err;
}
}
else
{
err = get_ftp_greeting (csock, con);
if (err != FTPOK)
return err;
}
#else
err = get_ftp_greeting (csock, con);
if (err != FTPOK)
return err;
#endif
/* Second: Login with proper USER/PASS sequence. */
logprintf (LOG_VERBOSE, _("Logging in as %s ... "),
quotearg_style (escape_quoting_style, user));
@@ -366,6 +513,46 @@ Error in server response, closing control connection.\n"));
default:
abort ();
}
#ifdef HAVE_SSL
if (using_control_security)
{
/* Send the PBSZ and PROT commands, in that order.
* If we are here it means that the server has already accepted
* some form of FTPS. Thus, these commands must work.
* If they don't work, that's an error. There's no sense in honoring
* --ftps-fallback-to-ftp or similar options. */
if (u->scheme == SCHEME_FTPS)
{
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PBSZ 0 ... ");
if ((err = ftp_pbsz (csock, 0)) == FTPNOPBSZ)
{
logputs (LOG_NOTQUIET, _("Server did not accept the 'PBSZ 0' command.\n"));
return err;
}
if (!opt.server_response)
logputs (LOG_VERBOSE, "done.");
if (!opt.server_response)
logprintf (LOG_VERBOSE, " ==> PROT %c ... ", prot);
if ((err = ftp_prot (csock, prot)) == FTPNOPROT)
{
logprintf (LOG_NOTQUIET, _("Server did not accept the 'PROT %c' command.\n"), prot);
return err;
}
if (!opt.server_response)
logputs (LOG_VERBOSE, "done.\n");
if (prot != PROT_CLEAR)
{
using_data_security = true;
con->st |= DATA_CHANNEL_SECURITY;
}
}
}
#endif
/* Third: Get the system type */
if (!opt.server_response)
logprintf (LOG_VERBOSE, "==> SYST ... ");
@@ -883,13 +1070,19 @@ Error in server response, closing control connection.\n"));
? CONERROR : CONIMPOSSIBLE);
}
pasv_mode_open = true; /* Flag to avoid accept port */
if (!opt.server_response)
logputs (LOG_VERBOSE, _("done. "));
} /* err==FTP_OK */
}
}
else
return err;
if (!pasv_mode_open) /* Try to use a port command if PASV failed */
/*
* We do not want to fall back from PASSIVE mode to ACTIVE mode !
* The reason is the PORT command exposes the client's real IP address
* to the server. Bad for someone who relies on privacy via a ftp proxy.
*/
}
else
{
err = ftp_do_port (csock, &local_sock);
/* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
@@ -1148,8 +1341,8 @@ Error in server response, closing control connection.\n"));
}
/* If no transmission was required, then everything is OK. */
if (!pasv_mode_open) /* we are not using pasive mode so we need
to accept */
if (!opt.ftp_pasv) /* we are not using passive mode so we need
to accept */
{
/* Wait for the server to connect to the address we're waiting
at. */
@@ -1308,6 +1501,38 @@ Error in server response, closing control connection.\n"));
else if (expected_bytes)
print_length (expected_bytes, restval, false);
#ifdef HAVE_SSL
if (u->scheme == SCHEME_FTPS && using_data_security)
{
/* We should try to restore the existing SSL session in the data connection
* and fall back to establishing a new session if the server doesn't want to restore it.
*/
if (!opt.ftps_resume_ssl || !ssl_connect_wget (dtsock, u->host, &csock))
{
if (opt.ftps_resume_ssl)
logputs (LOG_NOTQUIET, "Server does not want to resume the SSL session. Trying with a new one.\n");
if (!ssl_connect_wget (dtsock, u->host, NULL))
{
fd_close (csock);
fd_close (dtsock);
err = CONERROR;
logputs (LOG_NOTQUIET, "Could not perform SSL handshake.\n");
goto exit_error;
}
}
else
logputs (LOG_NOTQUIET, "Resuming SSL session in data connection.\n");
if (!ssl_check_certificate (dtsock, u->host))
{
fd_close (csock);
fd_close (dtsock);
err = CONERROR;
goto exit_error;
}
}
#endif
/* Get the contents of the document. */
flags = 0;
if (restval && rest_failed)
@@ -1372,10 +1597,18 @@ Error in server response, closing control connection.\n"));
become apparent later. */
if (*respline != '2')
{
xfree (respline);
if (res != -1)
logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
#ifdef HAVE_SSL
if (!c_strncasecmp (respline, "425", 3) && u->scheme == SCHEME_FTPS)
{
logputs (LOG_NOTQUIET, "FTPS server rejects new SSL sessions in the data connection.\n");
xfree (respline);
return FTPRESTFAIL;
}
#endif
xfree (respline);
return FTPRETRINT;
}
xfree (respline);
@@ -1532,6 +1765,13 @@ Error in server response, closing control connection.\n"));
}
} while (try_again);
return RETRFINISHED;
exit_error:
/* If fp is a regular file, close and try to remove it */
if (fp && !output_stream)
fclose (fp);
return err;
}
/* A one-file FTP loop. This is the part where FTP retrieval is
@@ -1540,7 +1780,8 @@ Error in server response, closing control connection.\n"));
This loop either gets commands from con, or (if ON_YOUR_OWN is
set), makes them up to retrieve the file given by the URL. */
static uerr_t
ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file)
ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file,
bool force_full_retrieve)
{
int count, orig_lp;
wgint restval, len = 0, qtyread = 0;
@@ -1642,6 +1883,8 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
/* Decide whether or not to restart. */
if (con->cmd & DO_LIST)
restval = 0;
else if (force_full_retrieve)
restval = 0;
else if (opt.start_pos >= 0)
restval = opt.start_pos;
else if (opt.always_rest
@@ -1692,11 +1935,17 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
switch (err)
{
case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
case UNLINKERR: case WARC_TMP_FWRITEERR:
case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case FTPNOAUTH: case FTPNOPBSZ: case FTPNOPROT:
case UNLINKERR: case WARC_TMP_FWRITEERR: case CONSSLERR: case CONTNOTSUPPORTED:
#ifdef HAVE_SSL
if (err == FTPNOAUTH)
logputs (LOG_NOTQUIET, "Server does not support AUTH TLS.\n");
if (opt.ftps_implicit)
logputs (LOG_NOTQUIET, "Server does not like implicit FTPS connections.\n");
#endif
/* Fatal errors, give up. */
if (warc_tmp != NULL)
fclose (warc_tmp);
fclose (warc_tmp);
return err;
case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
@@ -1771,10 +2020,12 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
warc_res = warc_write_resource_record (NULL, u->url, NULL, NULL,
warc_ip, NULL, warc_tmp, -1);
if (! warc_res)
return WARC_ERR;
/* warc_write_resource_record has also closed warc_tmp. */
warc_tmp = NULL;
}
if (con->cmd & DO_LIST)
@@ -1821,6 +2072,9 @@ Removing file due to --delete-after in ftp_loop_internal():\n"));
if (local_file)
*local_file = xstrdup (locf);
if (warc_tmp != NULL)
fclose (warc_tmp);
return RETROK;
} while (!opt.ntry || (count < opt.ntry));
@@ -1829,6 +2083,10 @@ Removing file due to --delete-after in ftp_loop_internal():\n"));
fd_close (con->csock);
con->csock = -1;
}
if (warc_tmp != NULL)
fclose (warc_tmp);
return TRYLIMEXC;
}
@@ -1856,7 +2114,7 @@ ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
con->target = xstrdup (lf);
xfree (lf);
err = ftp_loop_internal (u, NULL, con, NULL);
err = ftp_loop_internal (u, NULL, con, NULL, false);
lf = xstrdup (con->target);
xfree (con->target);
con->target = old_target;
@@ -1901,6 +2159,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
time_t tml;
bool dlthis; /* Download this (file). */
const char *actual_target = NULL;
bool force_full_retrieve = false;
/* Increase the depth. */
++depth;
@@ -1980,9 +2239,10 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
Remote file no newer than local file %s -- not retrieving.\n"), quote (con->target));
dlthis = false;
}
else if (eq_size)
else if (f->tstamp > tml)
{
/* Remote file is newer or sizes cannot be matched */
/* Remote file is newer */
force_full_retrieve = true;
logprintf (LOG_VERBOSE, _("\
Remote file is newer than local file %s -- retrieving.\n\n"),
quote (con->target));
@@ -2051,7 +2311,7 @@ Already have correct symlink %s -> %s\n\n"),
else /* opt.retr_symlinks */
{
if (dlthis)
err = ftp_loop_internal (u, f, con, NULL);
err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve);
} /* opt.retr_symlinks */
break;
case FT_DIRECTORY:
@@ -2062,7 +2322,7 @@ Already have correct symlink %s -> %s\n\n"),
case FT_PLAINFILE:
/* Call the retrieve loop. */
if (dlthis)
err = ftp_loop_internal (u, f, con, NULL);
err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve);
break;
case FT_UNKNOWN:
logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
@@ -2368,7 +2628,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
{
/* Let's try retrieving it anyway. */
con->st |= ON_YOUR_OWN;
res = ftp_loop_internal (u, NULL, con, NULL);
res = ftp_loop_internal (u, NULL, con, NULL, false);
return res;
}
@@ -2468,7 +2728,7 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
ispattern ? GLOB_GLOBALL : GLOB_GETONE);
}
else
res = ftp_loop_internal (u, NULL, &con, local_file);
res = ftp_loop_internal (u, NULL, &con, local_file, false);
}
if (res == FTPOK)
res = RETROK;

View File

@@ -1,7 +1,7 @@
/* Declarations for FTP support.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -33,6 +33,7 @@ as that of the covered work. */
#define FTP_H
#include "host.h"
#include "url.h"
/* System types. */
enum stype
@@ -53,10 +54,27 @@ enum ustype
UST_OTHER
};
#ifdef HAVE_SSL
/* Data channel protection levels (to be used with PBSZ) */
enum prot_level
{
PROT_CLEAR = 'C',
PROT_SAFE = 'S',
PROT_CONFIDENTIAL = 'E',
PROT_PRIVATE = 'P'
};
#endif
uerr_t ftp_response (int, char **);
uerr_t ftp_greeting (int);
uerr_t ftp_login (int, const char *, const char *);
uerr_t ftp_port (int, int *);
uerr_t ftp_pasv (int, ip_address *, int *);
#ifdef HAVE_SSL
uerr_t ftp_auth (int, enum url_scheme);
uerr_t ftp_pbsz (int, int);
uerr_t ftp_prot (int, enum prot_level);
#endif
#ifdef ENABLE_IPV6
uerr_t ftp_lprt (int, int *);
uerr_t ftp_lpsv (int, ip_address *, int *);
@@ -142,11 +160,12 @@ enum wget_ftp_fstatus
AVOID_LIST = 0x0008, /* It tells us if during this
session we have to avoid to use
"LIST". */
LIST_AFTER_LIST_A_CHECK_DONE = 0x0010
LIST_AFTER_LIST_A_CHECK_DONE = 0x0010,
/* It tells us if we have already
checked "LIST" after the first
"LIST -a" to handle the case of
file/folders named "-a". */
DATA_CHANNEL_SECURITY = 0x0020 /* Establish a secure data channel */
};
struct fileinfo *ftp_parse_ls (const char *, const enum stype);

View File

@@ -1,6 +1,6 @@
/* SSL support via GnuTLS library.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015
Free Software Foundation, Inc.
This file is part of GNU Wget.
@@ -56,6 +56,9 @@ as that of the covered work. */
#include "host.h"
static int
_do_handshake (gnutls_session_t session, int fd, double timeout);
static int
key_type_to_gnutls_type (enum keyfile_type type)
{
@@ -184,13 +187,13 @@ ssl_init (void)
/* Use the private key from the cert file unless otherwise specified. */
if (opt.cert_file && !opt.private_key)
{
opt.private_key = opt.cert_file;
opt.private_key = xstrdup (opt.cert_file);
opt.private_key_type = opt.cert_type;
}
/* Use the cert from the private key file unless otherwise specified. */
if (!opt.cert_file && opt.private_key)
{
opt.cert_file = opt.private_key;
opt.cert_file = xstrdup (opt.private_key);
opt.cert_type = opt.private_key_type;
}
@@ -219,6 +222,7 @@ cert to be of the same type.\n"));
struct wgnutls_transport_context
{
gnutls_session_t session; /* GnuTLS session handle */
gnutls_datum_t *session_data;
int last_error; /* last error returned by read/write/... */
/* Since GnuTLS doesn't support the equivalent to recv(...,
@@ -276,6 +280,12 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
{
ret = gnutls_record_recv (ctx->session, buf, bufsize);
timed_out = timeout && ptimer_measure (timer) >= timeout;
if (!timed_out && ret == GNUTLS_E_REHANDSHAKE)
{
DEBUGP (("GnuTLS: *** REHANDSHAKE while reading\n"));
if ((ret = _do_handshake (ctx->session, fd, timeout)) == 0)
ret = GNUTLS_E_AGAIN; /* restart reading */
}
}
}
while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
@@ -405,6 +415,11 @@ wgnutls_close (int fd, void *arg)
{
struct wgnutls_transport_context *ctx = arg;
/*gnutls_bye (ctx->session, GNUTLS_SHUT_RDWR);*/
if (ctx->session_data)
{
gnutls_free (ctx->session_data->data);
gnutls_free (ctx->session_data);
}
gnutls_deinit (ctx->session);
xfree (ctx);
close (fd);
@@ -419,16 +434,96 @@ static struct transport_implementation wgnutls_transport =
wgnutls_peek, wgnutls_errstr, wgnutls_close
};
bool
ssl_connect_wget (int fd, const char *hostname)
static int
_do_handshake (gnutls_session_t session, int fd, double timeout)
{
#ifdef F_GETFL
int flags = 0;
#endif
int err;
if (timeout)
{
#ifdef F_GETFL
flags = fcntl (fd, F_GETFL, 0);
if (flags < 0)
return flags;
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
return -1;
#else
/* XXX: Assume it was blocking before. */
const int one = 1;
if (ioctl (fd, FIONBIO, &one) < 0)
return -1;
#endif
}
/* We don't stop the handshake process for non-fatal errors */
do
{
err = gnutls_handshake (session);
if (timeout && err == GNUTLS_E_AGAIN)
{
if (gnutls_record_get_direction (session))
{
/* wait for writeability */
err = select_fd (fd, timeout, WAIT_FOR_WRITE);
}
else
{
/* wait for readability */
err = select_fd (fd, timeout, WAIT_FOR_READ);
}
if (err <= 0)
{
if (err == 0)
{
errno = ETIMEDOUT;
err = -1;
}
break;
}
err = GNUTLS_E_AGAIN;
}
else if (err < 0)
{
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
err == GNUTLS_E_FATAL_ALERT_RECEIVED)
{
gnutls_alert_description_t alert = gnutls_alert_get (session);
const char *str = gnutls_alert_get_name (alert);
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n",
alert, str ? str : "(unknown)");
}
}
}
while (err && gnutls_error_is_fatal (err) == 0);
if (timeout)
{
#ifdef F_GETFL
if (fcntl (fd, F_SETFL, flags) < 0)
return -1;
#else
const int zero = 0;
if (ioctl (fd, FIONBIO, &zero) < 0)
return -1;
#endif
}
return err;
}
bool
ssl_connect_wget (int fd, const char *hostname, int *continue_session)
{
struct wgnutls_transport_context *ctx;
gnutls_session_t session;
int err;
const char *str;
gnutls_init (&session, GNUTLS_CLIENT);
@@ -531,79 +626,32 @@ ssl_connect_wget (int fd, const char *hostname)
return false;
}
if (opt.connect_timeout)
if (continue_session)
{
#ifdef F_GETFL
flags = fcntl (fd, F_GETFL, 0);
if (flags < 0)
return flags;
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
return -1;
#else
/* XXX: Assume it was blocking before. */
const int one = 1;
if (ioctl (fd, FIONBIO, &one) < 0)
return -1;
#endif
}
/* We don't stop the handshake process for non-fatal errors */
do
{
err = gnutls_handshake (session);
if (opt.connect_timeout && err == GNUTLS_E_AGAIN)
ctx = (struct wgnutls_transport_context *) fd_transport_context (*continue_session);
if (!gnutls_session_is_resumed (session))
{
if (gnutls_record_get_direction (session))
if (!ctx || !ctx->session_data || gnutls_session_set_data (session, ctx->session_data->data, ctx->session_data->size))
{
/* wait for writeability */
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_WRITE);
}
else
{
/* wait for readability */
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_READ);
}
if (err <= 0)
{
if (err == 0)
if (ctx && ctx->session_data)
{
errno = ETIMEDOUT;
err = -1;
/* server does not want to continue the session */
if (ctx->session_data->data)
gnutls_free (ctx->session_data->data);
gnutls_free (ctx->session_data);
}
break;
gnutls_deinit (session);
return false;
}
err = GNUTLS_E_AGAIN;
}
else if (err < 0)
else
{
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
err == GNUTLS_E_FATAL_ALERT_RECEIVED)
{
gnutls_alert_description_t alert = gnutls_alert_get (session);
str = gnutls_alert_get_name (alert);
if (str == NULL)
str = "(unknown)";
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n", alert, str);
}
logputs (LOG_ALWAYS, "SSL session has already been resumed. Continuing.\n");
continue_session = NULL;
}
}
while (err && gnutls_error_is_fatal (err) == 0);
if (opt.connect_timeout)
{
#ifdef F_GETFL
if (fcntl (fd, F_SETFL, flags) < 0)
return -1;
#else
const int zero = 0;
if (ioctl (fd, FIONBIO, &zero) < 0)
return -1;
#endif
}
err = _do_handshake (session, fd, opt.connect_timeout);
if (err < 0)
{
@@ -612,7 +660,13 @@ ssl_connect_wget (int fd, const char *hostname)
}
ctx = xnew0 (struct wgnutls_transport_context);
ctx->session_data = xnew0 (gnutls_datum_t);
ctx->session = session;
if (gnutls_session_get_data2 (session, ctx->session_data))
{
xfree (ctx->session_data);
logprintf (LOG_NOTQUIET, "WARNING: Could not save SSL session data for socket %d\n", fd);
}
fd_register_transport (fd, &wgnutls_transport, ctx);
return true;
}
@@ -638,6 +692,10 @@ ssl_check_certificate (int fd, const char *host)
const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
bool success = true;
/* The user explicitly said to not check for the certificate. */
if (opt.check_cert == CHECK_CERT_QUIET)
return success;
err = gnutls_certificate_verify_peers2 (ctx->session, &status);
if (err < 0)
{
@@ -712,5 +770,5 @@ ssl_check_certificate (int fd, const char *host)
}
out:
return opt.check_cert ? success : true;
return opt.check_cert == CHECK_CERT_ON ? success : true;
}

View File

@@ -1,6 +1,6 @@
/* Hash tables.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
2009, 2010, 2011 Free Software Foundation, Inc.
2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* Hash table declarations.
Copyright (C) 2000, 2007, 2008, 2009, 2010, 2011 Free Software
Copyright (C) 2000, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Host name resolution and matching.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Declarations for host.c
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

768
src/hsts.c Normal file
View File

@@ -0,0 +1,768 @@
/* HTTP Strict Transport Security (HSTS) support.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
GNU Wget 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.
GNU Wget 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. */
#include "wget.h"
#ifdef HAVE_HSTS
#include "hsts.h"
#include "host.h" /* for is_valid_ip_address() */
#include "init.h" /* for home_dir() */
#include "utils.h"
#include "hash.h"
#include "c-ctype.h"
#ifdef TESTING
#include "test.h"
#endif
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#include <sys/file.h>
struct hsts_store {
struct hash_table *table;
time_t last_mtime;
};
struct hsts_kh {
char *host;
int explicit_port;
};
struct hsts_kh_info {
time_t created;
time_t max_age;
bool include_subdomains;
};
enum hsts_kh_match {
NO_MATCH,
SUPERDOMAIN_MATCH,
CONGRUENT_MATCH
};
#define hsts_is_host_name_valid(host) (!is_valid_ip_address (host))
#define hsts_is_scheme_valid(scheme) (scheme == SCHEME_HTTPS)
#define hsts_is_host_eligible(scheme, host) \
(hsts_is_scheme_valid (scheme) && hsts_is_host_name_valid (host))
#define DEFAULT_HTTP_PORT 80
#define DEFAULT_SSL_PORT 443
#define CHECK_EXPLICIT_PORT(p1, p2) (p1 == 0 || p1 == p2)
#define MAKE_EXPLICIT_PORT(s, p) (s == SCHEME_HTTPS ? (p == DEFAULT_SSL_PORT ? 0 : p) \
: (p == DEFAULT_HTTP_PORT ? 0 : p))
/* Hashing and comparison functions for the hash table */
static unsigned long
hsts_hash_func (const void *key)
{
struct hsts_kh *k = (struct hsts_kh *) key;
const char *h = NULL;
unsigned int hash = k->explicit_port;
for (h = k->host; *h; h++)
hash = hash * 31 + *h;
return hash;
}
static int
hsts_cmp_func (const void *h1, const void *h2)
{
struct hsts_kh *kh1 = (struct hsts_kh *) h1,
*kh2 = (struct hsts_kh *) h2;
return (!strcmp (kh1->host, kh2->host)) && (kh1->explicit_port == kh2->explicit_port);
}
/* Private functions. Feel free to make some of these public when needed. */
static struct hsts_kh_info *
hsts_find_entry (hsts_store_t store,
const char *host, int explicit_port,
enum hsts_kh_match *match_type,
struct hsts_kh *kh)
{
struct hsts_kh *k = NULL;
struct hsts_kh_info *khi = NULL;
enum hsts_kh_match match = NO_MATCH;
char *pos = NULL;
char *org_ptr = NULL;
k = (struct hsts_kh *) xnew (struct hsts_kh);
k->host = xstrdup_lower (host);
k->explicit_port = explicit_port;
/* save pointer so that we don't get into trouble later when freeing */
org_ptr = k->host;
khi = (struct hsts_kh_info *) hash_table_get (store->table, k);
if (khi)
{
match = CONGRUENT_MATCH;
goto end;
}
while (match == NO_MATCH &&
(pos = strchr (k->host, '.')) && pos - k->host > 0 &&
strchr (pos + 1, '.'))
{
k->host += (pos - k->host + 1);
khi = (struct hsts_kh_info *) hash_table_get (store->table, k);
if (khi)
match = SUPERDOMAIN_MATCH;
}
end:
/* restore pointer or we'll get a SEGV */
k->host = org_ptr;
/* copy parameters to previous frame */
if (match_type)
*match_type = match;
if (kh)
memcpy (kh, k, sizeof (struct hsts_kh));
else
xfree (k->host);
xfree (k);
return khi;
}
static bool
hsts_new_entry_internal (hsts_store_t store,
const char *host, int port,
time_t created, time_t max_age,
bool include_subdomains,
bool check_validity,
bool check_expired,
bool check_duplicates)
{
struct hsts_kh *kh = xnew (struct hsts_kh);
struct hsts_kh_info *khi = xnew0 (struct hsts_kh_info);
bool success = false;
kh->host = xstrdup_lower (host);
kh->explicit_port = MAKE_EXPLICIT_PORT (SCHEME_HTTPS, port);
khi->created = created;
khi->max_age = max_age;
khi->include_subdomains = include_subdomains;
/* Check validity */
if (check_validity && !hsts_is_host_name_valid (host))
goto bail;
if (check_expired && ((khi->created + khi->max_age) < khi->created))
goto bail;
if (check_duplicates && hash_table_contains (store->table, kh))
goto bail;
/* Now store the new entry */
hash_table_put (store->table, kh, khi);
success = true;
bail:
if (!success)
{
/* abort! */
xfree (kh->host);
xfree (kh);
xfree (khi);
}
return success;
}
/*
Creates a new entry, but does not check whether that entry already exists.
This function assumes that check has already been done by the caller.
*/
static bool
hsts_add_entry (hsts_store_t store,
const char *host, int port,
time_t max_age, bool include_subdomains)
{
time_t t = time (NULL);
/* It might happen time() returned -1 */
return (t < 0 ?
false :
hsts_new_entry_internal (store, host, port, t, max_age, include_subdomains, false, true, false));
}
/* Creates a new entry, unless an identical one already exists. */
static bool
hsts_new_entry (hsts_store_t store,
const char *host, int port,
time_t created, time_t max_age,
bool include_subdomains)
{
return hsts_new_entry_internal (store, host, port, created, max_age, include_subdomains, true, true, true);
}
static void
hsts_remove_entry (hsts_store_t store, struct hsts_kh *kh)
{
hash_table_remove (store->table, kh);
}
static bool
hsts_store_merge (hsts_store_t store,
const char *host, int port,
time_t created, time_t max_age,
bool include_subdomains)
{
enum hsts_kh_match match_type = NO_MATCH;
struct hsts_kh_info *khi = NULL;
bool success = false;
port = MAKE_EXPLICIT_PORT (SCHEME_HTTPS, port);
khi = hsts_find_entry (store, host, port, &match_type, NULL);
if (khi && match_type == CONGRUENT_MATCH && created > khi->created)
{
/* update the entry with the new info */
khi->created = created;
khi->max_age = max_age;
khi->include_subdomains = include_subdomains;
success = true;
}
else if (!khi)
success = hsts_new_entry (store, host, port, created, max_age, include_subdomains);
return success;
}
static bool
hsts_read_database (hsts_store_t store, FILE *fp, bool merge_with_existing_entries)
{
char *line = NULL, *p;
size_t len = 0;
int items_read;
bool result = false;
bool (*func)(hsts_store_t, const char *, int, time_t, time_t, bool);
char host[256];
int port;
time_t created, max_age;
int include_subdomains;
func = (merge_with_existing_entries ? hsts_store_merge : hsts_new_entry);
while (getline (&line, &len, fp) > 0)
{
for (p = line; c_isspace (*p); p++)
;
if (*p == '#')
continue;
items_read = sscanf (p, "%255s %d %d %lu %lu",
host,
&port,
&include_subdomains,
(unsigned long *) &created,
(unsigned long *) &max_age);
if (items_read == 5)
func (store, host, port, created, max_age, !!include_subdomains);
}
xfree (line);
result = true;
return result;
}
static void
hsts_store_dump (hsts_store_t store, FILE *fp)
{
hash_table_iterator it;
/* Print preliminary comments. We don't care if any of these fail. */
fputs ("# HSTS 1.0 Known Hosts database for GNU Wget.\n", fp);
fputs ("# Edit at your own risk.\n", fp);
fputs ("# <hostname>[:<port>]\t<incl. subdomains>\t<created>\t<max-age>\n", fp);
/* Now cycle through the HSTS store in memory and dump the entries */
for (hash_table_iterate (store->table, &it); hash_table_iter_next (&it);)
{
struct hsts_kh *kh = (struct hsts_kh *) it.key;
struct hsts_kh_info *khi = (struct hsts_kh_info *) it.value;
if (fprintf (fp, "%s\t%d\t%d\t%lu\t%lu\n",
kh->host, kh->explicit_port, khi->include_subdomains,
khi->created, khi->max_age) < 0)
{
logprintf (LOG_ALWAYS, "Could not write the HSTS database correctly.\n");
break;
}
}
}
/* HSTS API */
/*
Changes the given URLs according to the HSTS policy.
If there's no host in the store that either congruently
or not, matches the given URL, no changes are made.
Returns true if the URL was changed, or false
if it was left intact.
*/
bool
hsts_match (hsts_store_t store, struct url *u)
{
bool url_changed = false;
struct hsts_kh_info *entry = NULL;
struct hsts_kh *kh = xnew(struct hsts_kh);
enum hsts_kh_match match = NO_MATCH;
int port = MAKE_EXPLICIT_PORT (u->scheme, u->port);
/* avoid doing any computation if we're already in HTTPS */
if (!hsts_is_scheme_valid (u->scheme))
{
entry = hsts_find_entry (store, u->host, port, &match, kh);
if (entry)
{
if ((entry->created + entry->max_age) >= time(NULL))
{
if ((match == CONGRUENT_MATCH) ||
(match == SUPERDOMAIN_MATCH && entry->include_subdomains))
{
/* we found a matching Known HSTS Host
rewrite the URL */
u->scheme = SCHEME_HTTPS;
if (u->port == 80)
u->port = 443;
url_changed = true;
}
}
else
hsts_remove_entry (store, kh);
}
xfree (kh->host);
}
xfree (kh);
return url_changed;
}
/*
Add a new HSTS Known Host to the HSTS store.
If the host already exists, its information is updated,
or it'll be removed from the store if max_age is zero.
Bear in mind that the store is kept in memory, and will not
be written to disk until hsts_store_save is called.
This function regrows the in-memory HSTS store if necessary.
Currently, for a host to be taken into consideration,
two conditions have to be met:
- Connection must be through a secure channel (HTTPS).
- The host must not be an IPv4 or IPv6 address.
The RFC 6797 states that hosts that match IPv4 or IPv6 format
should be discarded at URI rewrite time. But we short-circuit
that check here, since there's no point in storing a host that
will never be matched.
Returns true if a new entry was actually created, or false
if an existing entry was updated/deleted. */
bool
hsts_store_entry (hsts_store_t store,
enum url_scheme scheme, const char *host, int port,
time_t max_age, bool include_subdomains)
{
bool result = false;
enum hsts_kh_match match = NO_MATCH;
struct hsts_kh *kh = xnew(struct hsts_kh);
struct hsts_kh_info *entry = NULL;
time_t t = 0;
if (hsts_is_host_eligible (scheme, host))
{
port = MAKE_EXPLICIT_PORT (scheme, port);
entry = hsts_find_entry (store, host, port, &match, kh);
if (entry && match == CONGRUENT_MATCH)
{
if (max_age == 0)
hsts_remove_entry (store, kh);
else if (max_age > 0)
{
entry->include_subdomains = include_subdomains;
if (entry->max_age != max_age)
{
/* RFC 6797 states that 'max_age' is a TTL relative to the reception of the STS header
so we have to update the 'created' field too */
t = time (NULL);
if (t != -1)
entry->created = t;
entry->max_age = max_age;
}
}
/* we ignore negative max_ages */
}
else if (entry == NULL || match == SUPERDOMAIN_MATCH)
{
/* Either we didn't find a matching host,
or we got a superdomain match.
In either case, we create a new entry.
We have to perform an explicit check because it might
happen we got a non-existent entry with max_age == 0.
*/
result = hsts_add_entry (store, host, port, max_age, include_subdomains);
}
/* we ignore new entries with max_age == 0 */
xfree (kh->host);
}
xfree (kh);
return result;
}
hsts_store_t
hsts_store_open (const char *filename)
{
hsts_store_t store = NULL;
struct_stat st;
FILE *fp = NULL;
store = xnew0 (struct hsts_store);
store->table = hash_table_new (0, hsts_hash_func, hsts_cmp_func);
store->last_mtime = 0;
if (file_exists_p (filename))
{
fp = fopen (filename, "r");
if (!fp || !hsts_read_database (store, fp, false))
{
/* abort! */
hsts_store_close (store);
xfree (store);
goto out;
}
if (fstat (fileno (fp), &st) == 0)
store->last_mtime = st.st_mtime;
fclose (fp);
}
out:
return store;
}
void
hsts_store_save (hsts_store_t store, const char *filename)
{
struct_stat st;
FILE *fp = NULL;
int fd = 0;
if (filename && hash_table_count (store->table) > 0)
{
fp = fopen (filename, "a+");
if (fp)
{
/* Lock the file to avoid potential race conditions */
fd = fileno (fp);
flock (fd, LOCK_EX);
/* If the file has changed, merge the changes with our in-memory data
before dumping them to the file.
Otherwise we could potentially overwrite the data stored by other Wget processes.
*/
if (store->last_mtime && stat (filename, &st) == 0 && st.st_mtime > store->last_mtime)
hsts_read_database (store, fp, true);
/* We've merged the latest changes so we can now truncate the file
and dump everything. */
fseek (fp, 0, SEEK_SET);
ftruncate (fd, 0);
/* now dump to the file */
hsts_store_dump (store, fp);
/* fclose is expected to unlock the file for us */
fclose (fp);
}
}
}
void
hsts_store_close (hsts_store_t store)
{
hash_table_iterator it;
/* free all the host fields */
for (hash_table_iterate (store->table, &it); hash_table_iter_next (&it);)
{
xfree (((struct hsts_kh *) it.key)->host);
xfree (it.key);
xfree (it.value);
}
hash_table_destroy (store->table);
}
#ifdef TESTING
/* I know I'm really evil because I'm writing macros
that change control flow. But we're testing, who will tell? :D
*/
#define TEST_URL_RW(s, u, p) do { \
if (test_url_rewrite (s, u, p, true)) \
return test_url_rewrite (s, u, p, true); \
} while (0)
#define TEST_URL_NORW(s, u, p) do { \
if (test_url_rewrite (s, u, p, false)) \
return test_url_rewrite (s, u, p, false); \
} while (0)
static char *
get_hsts_store_filename (void)
{
char *home = NULL, *filename = NULL;
FILE *fp = NULL;
home = home_dir ();
if (home)
{
filename = aprintf ("%s/.wget-hsts-test", home);
fp = fopen (filename, "w");
if (fp)
fclose (fp);
}
xfree (home);
return filename;
}
static hsts_store_t
open_hsts_test_store (void)
{
char *filename = NULL;
hsts_store_t table = NULL;
filename = get_hsts_store_filename ();
table = hsts_store_open (filename);
xfree (filename);
return table;
}
static void
close_hsts_test_store (hsts_store_t store)
{
char *filename = NULL;
filename = get_hsts_store_filename ();
unlink (filename);
xfree (filename);
xfree (store);
}
static const char*
test_url_rewrite (hsts_store_t s, const char *url, int port, bool rewrite)
{
bool result;
struct url u;
u.host = xstrdup (url);
u.port = port;
u.scheme = SCHEME_HTTP;
result = hsts_match (s, &u);
if (rewrite)
{
if (port == 80)
mu_assert("URL: port should've been rewritten to 443", u.port == 443);
else
mu_assert("URL: port should've been left intact", u.port == port);
mu_assert("URL: scheme should've been rewritten to HTTPS", u.scheme == SCHEME_HTTPS);
mu_assert("result should've been true", result == true);
}
else
{
mu_assert("URL: port should've been left intact", u.port == port);
mu_assert("URL: scheme should've been left intact", u.scheme == SCHEME_HTTP);
mu_assert("result should've been false", result == false);
}
xfree (u.host);
return NULL;
}
const char *
test_hsts_new_entry (void)
{
enum hsts_kh_match match = NO_MATCH;
struct hsts_kh_info *khi;
hsts_store_t s;
bool created;
s = open_hsts_test_store ();
mu_assert("Could not open the HSTS store. This could be due to lack of memory.", s != NULL);
created = hsts_store_entry (s, SCHEME_HTTP, "www.foo.com", 80, 1234, true);
mu_assert("No entry should have been created.", created == false);
created = hsts_store_entry (s, SCHEME_HTTPS, "www.foo.com", 443, 1234, true);
mu_assert("A new entry should have been created", created == true);
khi = hsts_find_entry (s, "www.foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been a congruent match", match == CONGRUENT_MATCH);
mu_assert("No valid HSTS info was returned", khi != NULL);
mu_assert("Variable 'max_age' should be 1234", khi->max_age == 1234);
mu_assert("Variable 'include_subdomains' should be asserted", khi->include_subdomains == true);
khi = hsts_find_entry (s, "b.www.foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been a superdomain match", match == SUPERDOMAIN_MATCH);
mu_assert("No valid HSTS info was returned", khi != NULL);
mu_assert("Variable 'max_age' should be 1234", khi->max_age == 1234);
mu_assert("Variable 'include_subdomains' should be asserted", khi->include_subdomains == true);
khi = hsts_find_entry (s, "ww.foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been no match", match == NO_MATCH);
khi = hsts_find_entry (s, "foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been no match", match == NO_MATCH);
khi = hsts_find_entry (s, ".foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been no match", match == NO_MATCH);
khi = hsts_find_entry (s, ".www.foo.com", MAKE_EXPLICIT_PORT (SCHEME_HTTPS, 443), &match, NULL);
mu_assert("Should've been no match", match == NO_MATCH);
hsts_store_close (s);
close_hsts_test_store (s);
return NULL;
}
const char*
test_hsts_url_rewrite_superdomain (void)
{
hsts_store_t s;
bool created;
s = open_hsts_test_store ();
mu_assert("Could not open the HSTS store", s != NULL);
created = hsts_store_entry (s, SCHEME_HTTPS, "www.foo.com", 443, 1234, true);
mu_assert("A new entry should've been created", created == true);
TEST_URL_RW (s, "www.foo.com", 80);
TEST_URL_RW (s, "bar.www.foo.com", 80);
hsts_store_close (s);
close_hsts_test_store (s);
return NULL;
}
const char*
test_hsts_url_rewrite_congruent (void)
{
hsts_store_t s;
bool created;
s = open_hsts_test_store ();
mu_assert("Could not open the HSTS store", s != NULL);
created = hsts_store_entry (s, SCHEME_HTTPS, "foo.com", 443, 1234, false);
mu_assert("A new entry should've been created", created == true);
TEST_URL_RW (s, "foo.com", 80);
TEST_URL_NORW (s, "www.foo.com", 80);
hsts_store_close (s);
close_hsts_test_store (s);
return NULL;
}
const char*
test_hsts_read_database (void)
{
hsts_store_t table;
char *home = home_dir();
char *file = NULL;
FILE *fp = NULL;
time_t created = time(NULL) - 10;
if (home)
{
file = aprintf ("%s/.wget-hsts-testing", home);
fp = fopen (file, "w");
if (fp)
{
fputs ("# dummy comment\n", fp);
fprintf (fp, "foo.example.com\t0\t1\t%ld\t123\n",(long) created);
fprintf (fp, "bar.example.com\t0\t0\t%ld\t456\n", (long) created);
fprintf (fp, "test.example.com\t8080\t0\t%ld\t789\n", (long) created);
fclose (fp);
table = hsts_store_open (file);
TEST_URL_RW (table, "foo.example.com", 80);
TEST_URL_RW (table, "www.foo.example.com", 80);
TEST_URL_RW (table, "bar.example.com", 80);
TEST_URL_NORW(table, "www.bar.example.com", 80);
TEST_URL_RW (table, "test.example.com", 8080);
hsts_store_close (table);
close_hsts_test_store (table);
unlink (file);
}
xfree (file);
xfree (home);
}
return NULL;
}
#endif /* TESTING */
#endif /* HAVE_HSTS */

53
src/hsts.h Normal file
View File

@@ -0,0 +1,53 @@
/* Declarations for hsts.c
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
GNU Wget 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.
GNU Wget 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. */
#include "wget.h"
#ifdef HAVE_HSTS
#ifndef HSTS_H
#define HSTS_H
#include "url.h"
typedef struct hsts_store *hsts_store_t;
hsts_store_t hsts_store_open (const char *);
void hsts_store_save (hsts_store_t, const char *);
void hsts_store_close (hsts_store_t);
bool hsts_store_entry (hsts_store_t,
enum url_scheme, const char *, int,
time_t, bool);
bool hsts_match (hsts_store_t, struct url *);
#endif /* HSTS_H */
#endif /* HAVE_HSTS */

View File

@@ -1,6 +1,6 @@
/* HTML parser for Wget.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Declarations for html-parse.c.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,7 @@
/* Collect URLs from HTML source.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.
@@ -303,6 +304,7 @@ append_url (const char *link_uri, int position, int size,
logprintf (LOG_NOTQUIET,
_("%s: Cannot resolve incomplete link %s.\n"),
ctx->document_file, link_uri);
iri_free (iri);
return NULL;
}
@@ -311,6 +313,7 @@ append_url (const char *link_uri, int position, int size,
{
DEBUGP (("%s: link \"%s\" doesn't parse.\n",
ctx->document_file, link_uri));
iri_free (iri);
return NULL;
}
}
@@ -334,6 +337,7 @@ append_url (const char *link_uri, int position, int size,
DEBUGP (("%s: merged link \"%s\" doesn't parse.\n",
ctx->document_file, complete_uri));
xfree (complete_uri);
iri_free (iri);
return NULL;
}
xfree (complete_uri);

View File

@@ -1,5 +1,5 @@
/* Declarations for html-url.c.
Copyright (C) 1995, 1996, 1997, 2009, 2010, 2011 Free Software
Copyright (C) 1995, 1996, 1997, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* NTLM code.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
Contributed by Daniel Stenberg.
This file is part of GNU Wget.
@@ -523,13 +523,13 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
0x0, 0x0,
#ifdef USE_NTRESPONSES
SHORTPAIR (0x18), /* NT-response length, twice */
SHORTPAIR (0x18), /* NT-response length, twice */
SHORTPAIR (0x18),
#else
0x0, 0x0,
0x0, 0x0,
0x0, 0x0,
#endif
SHORTPAIR (ntrespoff),
SHORTPAIR (ntrespoff),
0x0, 0x0,
SHORTPAIR (domlen),

View File

@@ -1,8 +1,8 @@
#ifndef __HTTP_NTLM_H
#define __HTTP_NTLM_H
/* Declarations for http_ntlm.c
Copyright (C) 1995, 1996, 1997, 2000, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Copyright (C) 1995, 1996, 1997, 2000, 2007, 2008, 2009, 2010, 2011,
2015 Free Software Foundation, Inc.
Contributed by Daniel Stenberg.
This file is part of GNU Wget.

2370
src/http.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* Declarations for HTTP.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -31,6 +31,8 @@ as that of the covered work. */
#ifndef HTTP_H
#define HTTP_H
#include "hsts.h"
struct url;
uerr_t http_loop (struct url *, struct url *, char **, char **, const char *,

View File

@@ -1,7 +1,7 @@
/* Reading/parsing the initialization file.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -115,6 +115,7 @@ CMD_DECLARE (cmd_spec_secure_protocol);
CMD_DECLARE (cmd_spec_timeout);
CMD_DECLARE (cmd_spec_useragent);
CMD_DECLARE (cmd_spec_verbose);
CMD_DECLARE (cmd_check_cert);
/* List of recognized commands, each consisting of name, place and
function. When adding a new command, simply add it to the list,
@@ -152,13 +153,14 @@ static const struct {
{ "cadirectory", &opt.ca_directory, cmd_directory },
{ "certificate", &opt.cert_file, cmd_file },
{ "certificatetype", &opt.cert_type, cmd_cert_type },
{ "checkcertificate", &opt.check_cert, cmd_boolean },
{ "checkcertificate", &opt.check_cert, cmd_check_cert },
#endif
{ "chooseconfig", &opt.choose_config, cmd_file },
{ "connecttimeout", &opt.connect_timeout, cmd_time },
{ "contentdisposition", &opt.content_disposition, cmd_boolean },
{ "contentonerror", &opt.content_on_error, cmd_boolean },
{ "continue", &opt.always_rest, cmd_boolean },
{ "convertfileonly", &opt.convert_file_only, cmd_boolean },
{ "convertlinks", &opt.convert_links, cmd_boolean },
{ "cookies", &opt.cookies, cmd_boolean },
#ifdef HAVE_SSL
@@ -188,12 +190,22 @@ static const struct {
{ "ftppasswd", &opt.ftp_passwd, cmd_string }, /* deprecated */
{ "ftppassword", &opt.ftp_passwd, cmd_string },
{ "ftpproxy", &opt.ftp_proxy, cmd_string },
#ifdef HAVE_SSL
{ "ftpscleardataconnection", &opt.ftps_clear_data_connection, cmd_boolean },
{ "ftpsfallbacktoftp", &opt.ftps_fallback_to_ftp, cmd_boolean },
{ "ftpsimplicit", &opt.ftps_implicit, cmd_boolean },
{ "ftpsresumessl", &opt.ftps_resume_ssl, cmd_boolean },
#endif
#ifdef __VMS
{ "ftpstmlf", &opt.ftp_stmlf, cmd_boolean },
#endif /* def __VMS */
{ "ftpuser", &opt.ftp_user, cmd_string },
{ "glob", &opt.ftp_glob, cmd_boolean },
{ "header", NULL, cmd_spec_header },
#ifdef HAVE_HSTS
{ "hsts", &opt.hsts, cmd_boolean },
{ "hsts-file", &opt.hsts_file, cmd_file },
#endif
{ "htmlextension", &opt.adjust_extension, cmd_boolean }, /* deprecated */
{ "htmlify", NULL, cmd_spec_htmlify },
{ "httpkeepalive", &opt.http_keep_alive, cmd_boolean },
@@ -205,6 +217,7 @@ static const struct {
#endif
{ "httpsproxy", &opt.https_proxy, cmd_string },
{ "httpuser", &opt.http_user, cmd_string },
{ "if-modified-since", &opt.if_modified_since, cmd_boolean },
{ "ignorecase", &opt.ignore_case, cmd_boolean },
{ "ignorelength", &opt.ignore_length, cmd_boolean },
{ "ignoretags", &opt.ignore_tags, cmd_vector },
@@ -214,6 +227,9 @@ static const struct {
{ "inet6only", &opt.ipv6_only, cmd_boolean },
#endif
{ "input", &opt.input_filename, cmd_file },
#ifdef HAVE_METALINK
{ "input-metalink", &opt.input_metalink, cmd_file },
#endif
{ "iri", &opt.enable_iri, cmd_boolean },
{ "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
{ "limitrate", &opt.limit_rate, cmd_bytes },
@@ -222,6 +238,9 @@ static const struct {
{ "logfile", &opt.lfilename, cmd_file },
{ "login", &opt.ftp_user, cmd_string },/* deprecated*/
{ "maxredirect", &opt.max_redirect, cmd_number },
#ifdef HAVE_METALINK
{ "metalink-over-http", &opt.metalink_over_http, cmd_boolean },
#endif
{ "method", &opt.method, cmd_string_uppercase },
{ "mirror", NULL, cmd_spec_mirror },
{ "netrc", &opt.netrc, cmd_boolean },
@@ -238,6 +257,9 @@ static const struct {
{ "postdata", &opt.post_data, cmd_string },
{ "postfile", &opt.post_file_name, cmd_file },
{ "preferfamily", NULL, cmd_spec_prefer_family },
#ifdef HAVE_METALINK
{ "preferred-location", &opt.preferred_location, cmd_string },
#endif
{ "preservepermissions", &opt.preserve_perm, cmd_boolean },
#ifdef HAVE_SSL
{ "privatekey", &opt.private_key, cmd_file },
@@ -260,6 +282,7 @@ static const struct {
{ "referer", &opt.referer, cmd_string },
{ "regextype", &opt.regex_type, cmd_spec_regex_type },
{ "reject", &opt.rejects, cmd_vector },
{ "rejectedlog", &opt.rejected_log, cmd_file },
{ "rejectregex", &opt.rejectregex_s, cmd_string },
{ "relativeonly", &opt.relative_only, cmd_boolean },
{ "remoteencoding", &opt.encoding_remote, cmd_string },
@@ -356,11 +379,13 @@ defaults (void)
opt.htmlify = true;
opt.http_keep_alive = true;
opt.use_proxy = true;
opt.convert_file_only = false;
tmp = getenv ("no_proxy");
if (tmp)
opt.no_proxy = sepstring (tmp);
opt.prefer_family = prefer_none;
opt.allow_cache = true;
opt.if_modified_since = true;
opt.read_timeout = 900;
opt.use_robots = true;
@@ -391,12 +416,18 @@ defaults (void)
opt.retr_symlinks = true;
#ifdef HAVE_SSL
opt.check_cert = true;
opt.check_cert = CHECK_CERT_ON;
opt.ftps_resume_ssl = true;
opt.ftps_fallback_to_ftp = false;
opt.ftps_implicit = false;
opt.ftps_clear_data_connection = false;
#endif
/* The default for file name restriction defaults to the OS type. */
#if defined(WINDOWS) || defined(MSDOS) || defined(__CYGWIN__)
opt.restrict_files_os = restrict_windows;
#elif defined(__VMS)
opt.restrict_files_os = restrict_vms;
#else
opt.restrict_files_os = restrict_unix;
#endif
@@ -437,6 +468,11 @@ defaults (void)
opt.start_pos = -1;
opt.show_progress = -1;
opt.noscroll = false;
#ifdef HAVE_HSTS
/* HSTS is enabled by default */
opt.hsts = true;
#endif
}
/* Return the user's home directory (strdup-ed), or NULL if none is
@@ -562,9 +598,7 @@ wgetrc_file_name (void)
SYSTEM_WGETRC should not be defined under WINDOWS. */
if (!file)
{
char *home = home_dir ();
xfree (file);
home = ws_mypath ();
char *home = ws_mypath ();
if (home)
{
file = aprintf ("%s/wget.ini", home);
@@ -922,6 +956,18 @@ static bool simple_atof (const char *, const char *, double *);
&& (p)[3] == '\0')
static int
cmd_boolean_internal (const char *com _GL_UNUSED, const char *val, void *place _GL_UNUSED)
{
if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
/* "on", "yes" and "1" mean true. */
return 1;
else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
/* "off", "no" and "0" mean false. */
return 0;
return -1;
}
/* Store the boolean value from VAL to PLACE. COM is ignored,
except for error messages. */
static bool
@@ -929,24 +975,62 @@ cmd_boolean (const char *com, const char *val, void *place)
{
bool value;
if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
/* "on", "yes" and "1" mean true. */
value = true;
else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
/* "off", "no" and "0" mean false. */
value = false;
else
switch (cmd_boolean_internal (com, val, place))
{
fprintf (stderr,
_("%s: %s: Invalid boolean %s; use `on' or `off'.\n"),
exec_name, com, quote (val));
return false;
}
case 0:
value = false;
break;
case 1:
value = true;
break;
default:
{
fprintf (stderr,
_("%s: %s: Invalid boolean %s; use `on' or `off'.\n"),
exec_name, com, quote (val));
return false;
}
}
*(bool *) place = value;
return true;
}
/* Store the check_cert value from VAL to PLACE. COM is ignored,
except for error messages. */
static bool
cmd_check_cert (const char *com, const char *val, void *place)
{
int value;
switch (cmd_boolean_internal (com, val, place))
{
case 0:
value = CHECK_CERT_OFF;
break;
case 1:
value = CHECK_CERT_ON;
break;
default:
{
if (!c_strcasecmp (val, "quiet"))
value = CHECK_CERT_QUIET;
else
{
fprintf (stderr,
_("%s: %s: Invalid %s; use `on', `off' or `quiet'.\n"),
exec_name, com, quote (val));
return false;
}
}
}
*(int *) place = value;
return true;
}
/* Set the non-negative integer value from VAL to PLACE. With
incorrect specification, the number remains unchanged. */
static bool
@@ -1481,6 +1565,8 @@ cmd_spec_restrict_file_names (const char *com, const char *val, void *place_igno
if (VAL_IS ("unix"))
restrict_os = restrict_unix;
else if (VAL_IS ("vms"))
restrict_os = restrict_vms;
else if (VAL_IS ("windows"))
restrict_os = restrict_windows;
else if (VAL_IS ("lowercase"))
@@ -1495,7 +1581,7 @@ cmd_spec_restrict_file_names (const char *com, const char *val, void *place_igno
{
fprintf (stderr, _("\
%s: %s: Invalid restriction %s,\n\
use [unix|windows],[lowercase|uppercase],[nocontrol],[ascii].\n"),
use [unix|vms|windows],[lowercase|uppercase],[nocontrol],[ascii].\n"),
exec_name, com, quote (val));
return false;
}
@@ -1789,6 +1875,10 @@ cleanup (void)
xfree (opt.lfilename);
xfree (opt.dir_prefix);
xfree (opt.input_filename);
#ifdef HAVE_METALINK
xfree (opt.input_metalink);
xfree (opt.preferred_location);
#endif
xfree (opt.output_document);
free_vec (opt.accepts);
free_vec (opt.rejects);
@@ -1830,6 +1920,7 @@ cleanup (void)
xfree (opt.post_data);
xfree (opt.body_data);
xfree (opt.body_file);
xfree (opt.rejected_log);
#endif /* DEBUG_MALLOC */
}

View File

@@ -1,7 +1,7 @@
/* Declarations for init.c.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

125
src/iri.c
View File

@@ -1,5 +1,6 @@
/* IRI related functions.
Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2008, 2009, 2010, 2011, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.
@@ -52,8 +53,9 @@ as that of the covered work. */
/* Given a string containing "charset=XXX", return the encoding if found,
or NULL otherwise */
char *
parse_charset (char *str)
parse_charset (const char *str)
{
const char *end;
char *charset;
if (!str || !*str)
@@ -64,14 +66,14 @@ parse_charset (char *str)
return NULL;
str += 8;
charset = str;
end = str;
/* sXXXav: which chars should be banned ??? */
while (*charset && !c_isspace (*charset))
charset++;
while (*end && !c_isspace (*end))
end++;
/* sXXXav: could strdupdelim return NULL ? */
charset = strdupdelim (str, charset);
charset = strdupdelim (str, end);
/* Do a minimum check on the charset value */
if (!check_encoding_name (charset))
@@ -94,9 +96,9 @@ find_locale (void)
/* Basic check of an encoding name. */
bool
check_encoding_name (char *encoding)
check_encoding_name (const char *encoding)
{
char *s = encoding;
const char *s = encoding;
while (*s)
{
@@ -116,13 +118,13 @@ check_encoding_name (char *encoding)
will contain the transcoded string on success. *out content is
unspecified otherwise. */
static bool
do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen, char **out)
do_conversion (const char *tocode, const char *fromcode, char const *in_org, size_t inlen, char **out)
{
iconv_t cd;
/* sXXXav : hummm hard to guess... */
size_t len, done, outlen;
int invalid = 0, tooshort = 0;
char *s, *in_org, *in_save;
char *s, *in, *in_save;
cd = iconv_open (tocode, fromcode);
if (cd == (iconv_t)(-1))
@@ -134,9 +136,8 @@ do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen,
}
/* iconv() has to work on an unescaped string */
in_org = in;
in_save = in = xstrndup(in, inlen);
url_unescape(in);
in_save = in = xstrndup (in_org, inlen);
url_unescape_except_reserved (in);
inlen = strlen(in);
len = outlen = inlen * 2;
@@ -151,7 +152,14 @@ do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen,
*(s + len - outlen - done) = '\0';
xfree(in_save);
iconv_close(cd);
DEBUGP (("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode));
IF_DEBUG
{
/* not not print out embedded passwords, in_org might be an URL */
if (!strchr(in_org, '@') && !strchr(*out, '@'))
debug_logprintf ("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode);
else
debug_logprintf ("%s: logging suppressed, strings may contain password\n", __func__);
}
return true;
}
@@ -192,7 +200,14 @@ do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen,
xfree(in_save);
iconv_close(cd);
DEBUGP (("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode));
IF_DEBUG
{
/* not not print out embedded passwords, in_org might be an URL */
if (!strchr(in_org, '@') && !strchr(*out, '@'))
debug_logprintf ("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode);
else
debug_logprintf ("%s: logging suppressed, strings may contain password\n", __func__);
}
return false;
}
@@ -216,42 +231,96 @@ locale_to_utf8 (const char *str)
if (do_conversion ("UTF-8", opt.locale, (char *) str, strlen ((char *) str), &new))
return (const char *) new;
xfree (new);
return str;
}
/*
* Work around a libidn <= 1.30 vulnerability.
*
* The function checks for a valid UTF-8 character sequence before
* passing it to idna_to_ascii_8z().
*
* [1] http://lists.gnu.org/archive/html/help-libidn/2015-05/msg00002.html
* [2] https://lists.gnu.org/archive/html/bug-wget/2015-06/msg00002.html
* [3] http://curl.haxx.se/mail/lib-2015-06/0143.html
*/
static bool
_utf8_is_valid(const char *utf8)
{
const unsigned char *s = (const unsigned char *) utf8;
while (*s)
{
if ((*s & 0x80) == 0) /* 0xxxxxxx ASCII char */
s++;
else if ((*s & 0xE0) == 0xC0) /* 110xxxxx 10xxxxxx */
{
if ((s[1] & 0xC0) != 0x80)
return false;
s+=2;
}
else if ((*s & 0xF0) == 0xE0) /* 1110xxxx 10xxxxxx 10xxxxxx */
{
if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80)
return false;
s+=3;
}
else if ((*s & 0xF8) == 0xF0) /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
{
if ((s[1] & 0xC0) != 0x80 || (s[2] & 0xC0) != 0x80 || (s[3] & 0xC0) != 0x80)
return false;
s+=4;
}
else
return false;
}
return true;
}
/* Try to "ASCII encode" UTF-8 host. Return the new domain on success or NULL
on error. */
char *
idn_encode (struct iri *i, char *host)
idn_encode (const struct iri *i, const char *host)
{
char *new;
int ret;
char *ascii_encoded;
char *utf8_encoded = NULL;
/* Encode to UTF-8 if not done */
if (!i->utf8_encode)
{
if (!remote_to_utf8 (i, (const char *) host, (const char **) &new))
if (!remote_to_utf8 (i, host, &utf8_encoded))
return NULL; /* Nothing to encode or an error occured */
host = new;
}
/* toASCII UTF-8 NULL terminated string */
ret = idna_to_ascii_8z (host, &new, IDNA_FLAGS);
if (!_utf8_is_valid(utf8_encoded ? utf8_encoded : host))
{
logprintf (LOG_VERBOSE, _("Invalid UTF-8 sequence: %s\n"),
quote(utf8_encoded ? utf8_encoded : host));
xfree (utf8_encoded);
return NULL;
}
/* Store in ascii_encoded the ASCII UTF-8 NULL terminated string */
ret = idna_to_ascii_8z (utf8_encoded ? utf8_encoded : host, &ascii_encoded, IDNA_FLAGS);
xfree (utf8_encoded);
if (ret != IDNA_SUCCESS)
{
/* sXXXav : free new when needed ! */
logprintf (LOG_VERBOSE, _("idn_encode failed (%d): %s\n"), ret,
quote (idna_strerror (ret)));
return NULL;
}
return new;
return ascii_encoded;
}
/* Try to decode an "ASCII encoded" host. Return the new domain in the locale
on success or NULL on error. */
char *
idn_decode (char *host)
idn_decode (const char *host)
{
char *new;
int ret;
@@ -270,7 +339,7 @@ idn_decode (char *host)
/* Try to transcode string str from remote encoding to UTF-8. On success, *new
contains the transcoded string. *new content is unspecified otherwise. */
bool
remote_to_utf8 (struct iri *iri, const char *str, const char **new)
remote_to_utf8 (const struct iri *iri, const char *str, char **new)
{
bool ret = false;
@@ -292,7 +361,7 @@ remote_to_utf8 (struct iri *iri, const char *str, const char **new)
return false;
}
if (do_conversion ("UTF-8", iri->uri_encoding, (char *) str, strlen (str), (char **) new))
if (do_conversion ("UTF-8", iri->uri_encoding, str, strlen (str), new))
ret = true;
/* Test if something was converted */
@@ -344,7 +413,7 @@ iri_free (struct iri *i)
/* Set uri_encoding of struct iri i. If a remote encoding was specified, use
it unless force is true. */
void
set_uri_encoding (struct iri *i, char *charset, bool force)
set_uri_encoding (struct iri *i, const char *charset, bool force)
{
DEBUGP (("URI encoding = %s\n", charset ? quote (charset) : "None"));
if (!force && opt.encoding_remote)
@@ -361,7 +430,7 @@ set_uri_encoding (struct iri *i, char *charset, bool force)
/* Set content_encoding of struct iri i. */
void
set_content_encoding (struct iri *i, char *charset)
set_content_encoding (struct iri *i, const char *charset)
{
DEBUGP (("URI content encoding = %s\n", charset ? quote (charset) : "None"));
if (opt.encoding_remote)

View File

@@ -1,5 +1,6 @@
/* Internationalization related declarations.
Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 2008, 2009, 2010, 2011, 2015 Free Software Foundation,
Inc.
This file is part of GNU Wget.
@@ -42,18 +43,18 @@ struct iri {
# include <idna.h>
# include <idn-free.h>
char *parse_charset (char *str);
char *parse_charset (const char *str);
char *find_locale (void);
bool check_encoding_name (char *encoding);
bool check_encoding_name (const char *encoding);
const char *locale_to_utf8 (const char *str);
char *idn_encode (struct iri *i, char *host);
char *idn_decode (char *host);
bool remote_to_utf8 (struct iri *i, const char *str, const char **new);
char *idn_encode (const struct iri *i, const char *host);
char *idn_decode (const char *host);
bool remote_to_utf8 (const struct iri *i, const char *str, char **new);
struct iri *iri_new (void);
struct iri *iri_dup (const struct iri *);
void iri_free (struct iri *i);
void set_uri_encoding (struct iri *i, char *charset, bool force);
void set_content_encoding (struct iri *i, char *charset);
void set_uri_encoding (struct iri *i, const char *charset, bool force);
void set_content_encoding (struct iri *i, const char *charset);
#else /* ENABLE_IRI */

View File

@@ -1,6 +1,6 @@
/* Messages logging.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
@@ -598,11 +598,18 @@ log_init (const char *file, bool appendp)
{
if (file)
{
logfp = fopen (file, appendp ? "a" : "w");
if (!logfp)
if (HYPHENP (file))
{
fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
exit (WGET_EXIT_GENERIC_ERROR);
logfp = stdout;
}
else
{
logfp = fopen (file, appendp ? "a" : "w");
if (!logfp)
{
fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
exit (WGET_EXIT_GENERIC_ERROR);
}
}
}
else

View File

@@ -1,6 +1,6 @@
/* Declarations for log.c.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2007, 2008, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,7 @@
/* Command line parsing.
Copyright (C) 1996-2014 Free Software Foundation, Inc.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -52,6 +54,7 @@ as that of the covered work. */
#include "convert.h"
#include "spider.h"
#include "http.h" /* for save_cookies */
#include "hsts.h" /* for initializing hsts_store to NULL */
#include "ptimer.h"
#include "warc.h"
#include "version.h"
@@ -61,6 +64,11 @@ as that of the covered work. */
#include <getpass.h>
#include <quote.h>
#ifdef HAVE_METALINK
# include <metalink/metalink_parser.h>
# include "metalink.h"
#endif
#ifdef WINDOWS
# include <io.h>
# include <fcntl.h>
@@ -134,6 +142,72 @@ i18n_initialize (void)
#endif /* ENABLE_NLS */
}
#ifdef HAVE_HSTS
/* make the HSTS store global */
hsts_store_t hsts_store;
static char*
get_hsts_database (void)
{
char *home;
if (opt.hsts_file)
return xstrdup (opt.hsts_file);
home = home_dir ();
if (home)
{
char *dir = aprintf ("%s/.wget-hsts", home);
xfree(home);
return dir;
}
return NULL;
}
static void
load_hsts (void)
{
if (!hsts_store)
{
char *filename = get_hsts_database ();
if (filename)
{
DEBUGP (("Reading HSTS entries from %s\n", filename));
hsts_store = hsts_store_open (filename);
if (!hsts_store)
logprintf (LOG_NOTQUIET, "ERROR: could not open HSTS store at '%s'. "
"HSTS will be disabled.\n",
filename);
}
else
logprintf (LOG_NOTQUIET, "ERROR: could not open HSTS store. HSTS will be disabled.\n");
xfree (filename);
}
}
static void
save_hsts (void)
{
if (hsts_store)
{
char *filename = get_hsts_database ();
if (filename)
DEBUGP (("Saving HSTS entries to %s\n", filename));
hsts_store_save (hsts_store, filename);
hsts_store_close (hsts_store);
xfree (filename);
}
}
#endif
/* Definition of command-line options. */
static void _Noreturn print_help (void);
@@ -190,6 +264,7 @@ static struct cmdline_option option_data[] =
{ "config", 0, OPT_VALUE, "chooseconfig", -1 },
{ "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
{ "continue", 'c', OPT_BOOLEAN, "continue", -1 },
{ "convert-file-only", 0, OPT_BOOLEAN, "convertfileonly", -1 },
{ "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
{ "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
{ "content-on-error", 0, OPT_BOOLEAN, "contentonerror", -1 },
@@ -219,10 +294,20 @@ static struct cmdline_option option_data[] =
{ "ftp-stmlf", 0, OPT_BOOLEAN, "ftpstmlf", -1 },
#endif /* def __VMS */
{ "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
#ifdef HAVE_SSL
{ "ftps-clear-data-connection", 0, OPT_BOOLEAN, "ftpscleardataconnection", -1 },
{ "ftps-fallback-to-ftp", 0, OPT_BOOLEAN, "ftpsfallbacktoftp", -1 },
{ "ftps-implicit", 0, OPT_BOOLEAN, "ftpsimplicit", -1 },
{ "ftps-resume-ssl", 0, OPT_BOOLEAN, "ftpsresumessl", -1 },
#endif
{ "glob", 0, OPT_BOOLEAN, "glob", -1 },
{ "header", 0, OPT_VALUE, "header", -1 },
{ "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
{ "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
#ifdef HAVE_HSTS
{ "hsts", 0, OPT_BOOLEAN, "hsts", -1},
{ "hsts-file", 0, OPT_VALUE, "hsts-file", -1 },
#endif
{ "html-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 }, /* deprecated */
{ "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
{ "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
@@ -239,13 +324,20 @@ static struct cmdline_option option_data[] =
{ "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
#endif
{ "input-file", 'i', OPT_VALUE, "input", -1 },
#ifdef HAVE_METALINK
{ "input-metalink", 0, OPT_VALUE, "input-metalink", -1 },
#endif
{ "iri", 0, OPT_BOOLEAN, "iri", -1 },
{ "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
{ "level", 'l', OPT_VALUE, "reclevel", -1 },
{ "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
{ "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
{ "local-encoding", 0, OPT_VALUE, "localencoding", -1 },
{ "rejected-log", 0, OPT_VALUE, "rejectedlog", -1 },
{ "max-redirect", 0, OPT_VALUE, "maxredirect", -1 },
#ifdef HAVE_METALINK
{ "metalink-over-http", 0, OPT_BOOLEAN, "metalink-over-http", -1 },
#endif
{ "method", 0, OPT_VALUE, "method", -1 },
{ "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
{ "no", 'n', OPT__NO, NULL, required_argument },
@@ -261,6 +353,9 @@ static struct cmdline_option option_data[] =
{ "post-data", 0, OPT_VALUE, "postdata", -1 },
{ "post-file", 0, OPT_VALUE, "postfile", -1 },
{ "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
#ifdef HAVE_METALINK
{ "preferred-location", 0, OPT_VALUE, "preferred-location", -1 },
#endif
{ "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
{ IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
{ IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
@@ -299,6 +394,7 @@ static struct cmdline_option option_data[] =
{ "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
{ "timeout", 'T', OPT_VALUE, "timeout", -1 },
{ "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
{ "if-modified-since", 0, OPT_BOOLEAN, "if-modified-since", -1 },
{ "tries", 't', OPT_VALUE, "tries", -1 },
{ "unlink", 0, OPT_BOOLEAN, "unlink", -1 },
{ "trust-server-names", 0, OPT_BOOLEAN, "trustservernames", -1 },
@@ -340,8 +436,7 @@ no_prefix (const char *s)
char *cp = p;
int size = 3 + strlen (s) + 1; /* "no-STRING\0" */
if (p + size >= buffer + sizeof (buffer))
abort ();
assert(p + size <= buffer + sizeof (buffer));
cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
strcpy (cp + 3, s);
@@ -481,6 +576,10 @@ Logging and input file:\n"),
--report-speed=TYPE output bandwidth as TYPE. TYPE can be bits\n"),
N_("\
-i, --input-file=FILE download URLs found in local or external FILE\n"),
#ifdef HAVE_METALINK
N_("\
--input-metalink=FILE download files covered in local Metalink FILE\n"),
#endif
N_("\
-F, --force-html treat input file as HTML\n"),
N_("\
@@ -490,6 +589,8 @@ Logging and input file:\n"),
--config=FILE specify config file to use\n"),
N_("\
--no-config do not read any config file\n"),
N_("\
--rejected-log=FILE log reasons for URL rejection to FILE\n"),
"\n",
N_("\
@@ -515,7 +616,10 @@ Download:\n"),
-N, --timestamping don't re-retrieve files unless newer than\n\
local\n"),
N_("\
--no-use-server-timestamps don't set the local file's timestamp by\n\
--no-if-modified-since don't use conditional if-modified-since get\n\
requests in timestamping mode\n"),
N_("\
--no-use-server-timestamps don't set the local file's timestamp by\n\
the one on the server\n"),
N_("\
-S, --server-response print server response\n"),
@@ -572,6 +676,12 @@ Download:\n"),
--remote-encoding=ENC use ENC as the default remote encoding\n"),
N_("\
--unlink remove file before clobber\n"),
#ifdef HAVE_METALINK
N_("\
--metalink-over-http use Metalink metadata from HTTP response headers\n"),
N_("\
--preferred-location preferred location for Metalink resources\n"),
#endif
"\n",
N_("\
@@ -685,6 +795,16 @@ HTTPS (SSL/TLS) options:\n"),
"\n",
#endif /* HAVE_SSL */
#ifdef HAVE_HSTS
N_("\
HSTS options:\n"),
N_("\
--no-hsts disable HSTS\n"),
N_("\
--hsts-file path of HSTS database (will override default)\n"),
"\n",
#endif
N_("\
FTP options:\n"),
#ifdef __VMS
@@ -707,6 +827,20 @@ FTP options:\n"),
--retr-symlinks when recursing, get linked-to files (not dir)\n"),
"\n",
#ifdef HAVE_SSL
N_("\
FTPS options:\n"),
N_("\
--ftps-implicit use implicit FTPS (default port is 990)\n"),
N_("\
--ftps-resume-ssl resume the SSL/TLS session started in the control connection when\n"
" opening a data connection\n"),
N_("\
--ftps-clear-data-connection cipher the control channel only; all the data will be in plaintext\n"),
N_("\
--ftps-fallback-to-ftp fall back to FTP if FTPS is not supported in the target server\n"),
#endif
N_("\
WARC options:\n"),
N_("\
@@ -743,6 +877,8 @@ Recursive download:\n"),
N_("\
-k, --convert-links make links in downloaded HTML or CSS point to\n\
local files\n"),
N_("\
--convert-file-only convert the file part of the URLs only (usually known as the basename)\n"),
N_("\
--backups=N before writing file X, rotate up to N backup files\n"),
@@ -874,7 +1010,10 @@ format_and_print_line (const char *prefix, const char *line,
line_dup = xstrdup (line);
if (printf ("%s", prefix) < 0)
return -1;
{
xfree (line_dup);
return -1;
}
/* Wrap to new line after prefix. */
remaining_chars = 0;
@@ -889,7 +1028,10 @@ format_and_print_line (const char *prefix, const char *line,
if (remaining_chars <= (int) strlen (token))
{
if (printf ("\n%*c", TABULATION, ' ') < 0)
return -1;
{
xfree (line_dup);
return -1;
}
remaining_chars = line_length - TABULATION;
}
if (printf ("%s ", token) < 0)
@@ -902,7 +1044,10 @@ format_and_print_line (const char *prefix, const char *line,
}
if (printf ("\n") < 0)
return -1;
{
xfree (line_dup);
return -1;
}
xfree (line_dup);
return 0;
@@ -986,7 +1131,7 @@ print_version (void)
/* TRANSLATORS: When available, an actual copyright character
(circle-c) should be used in preference to "(C)". */
if (printf (_("\
Copyright (C) %s Free Software Foundation, Inc.\n"), "2014") < 0)
Copyright (C) %s Free Software Foundation, Inc.\n"), "2015") < 0)
exit (WGET_EXIT_IO_FAIL);
if (fputs (_("\
License GPLv3+: GNU GPL version 3 or later\n\
@@ -1245,11 +1390,14 @@ main (int argc, char **argv)
/* All user options have now been processed, so it's now safe to do
interoption dependency checks. */
if (opt.noclobber && opt.convert_links)
if (opt.noclobber && (opt.convert_links || opt.convert_file_only))
{
fprintf (stderr,
_("Both --no-clobber and --convert-links were specified,"
" only --convert-links will be used.\n"));
opt.convert_links ?
_("Both --no-clobber and --convert-links were specified,"
" only --convert-links will be used.\n") :
_("Both --no-clobber and --convert-file-only were specified,"
" only --convert-file-only will be used.\n"));
opt.noclobber = false;
}
@@ -1272,6 +1420,12 @@ main (int argc, char **argv)
if (opt.verbose == -1)
opt.verbose = !opt.quiet;
if (!opt.verbose && opt.show_progress == -1)
opt.show_progress = false;
if (opt.quiet && opt.show_progress == -1)
opt.show_progress = false;
/* Sanity checks. */
if (opt.verbose && opt.quiet)
{
@@ -1297,11 +1451,11 @@ Can't timestamp and not clobber old files at the same time.\n"));
#endif
if (opt.output_document)
{
if (opt.convert_links
if ((opt.convert_links || opt.convert_file_only)
&& (nurl > 1 || opt.page_requisites || opt.recursive))
{
fputs (_("\
Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
Cannot specify both -k or --convert-file-only and -O if multiple URLs are given, or in combination\n\
with -p or -r. See the manual for details.\n\n"), stderr);
print_usage (1);
exit (WGET_EXIT_GENERIC_ERROR);
@@ -1388,7 +1542,11 @@ for details.\n\n"));
opt.always_rest = false;
}
if (!nurl && !opt.input_filename)
if (!nurl && !opt.input_filename
#ifdef HAVE_METALINK
&& !opt.input_metalink
#endif
)
{
/* No URL specified. */
fprintf (stderr, _("%s: missing URL\n"), exec_name);
@@ -1602,11 +1760,16 @@ for details.\n\n"));
if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
output_stream_regular = true;
}
if (!output_stream_regular && opt.convert_links)
if (!output_stream_regular && (opt.convert_links || opt.recursive))
{
fprintf (stderr, _("-k can be used together with -O only if \
fprintf (stderr, _("-k or -r can be used together with -O only if \
outputting to a regular file.\n"));
print_usage (1);
exit (WGET_EXIT_GENERIC_ERROR);
}
if (!output_stream_regular && (opt.convert_links || opt.convert_file_only))
{
fprintf (stderr, _("--convert-links or --convert-file-only can be used together \
only if outputting to a regular file.\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
}
@@ -1645,6 +1808,16 @@ outputting to a regular file.\n"));
signal (SIGWINCH, progress_handle_sigwinch);
#endif
#ifdef HAVE_HSTS
/* Load the HSTS database.
Maybe all the URLs are FTP(S), in which case HSTS would not be needed,
but this is the best place to do it, and it shouldn't be a critical
performance hit.
*/
if (opt.hsts)
load_hsts ();
#endif
/* Retrieve the URLs from argument list. */
for (t = url; *t; t++)
{
@@ -1669,12 +1842,21 @@ outputting to a regular file.\n"));
else
{
if ((opt.recursive || opt.page_requisites)
&& (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (url_parsed)))
&& ((url_scheme (*t) != SCHEME_FTP
#ifdef HAVE_SSL
&& url_scheme (*t) != SCHEME_FTPS
#endif
)
|| url_uses_proxy (url_parsed)))
{
int old_follow_ftp = opt.follow_ftp;
/* Turn opt.follow_ftp on in case of recursive FTP retrieval */
if (url_scheme (*t) == SCHEME_FTP)
if (url_scheme (*t) == SCHEME_FTP
#ifdef HAVE_SSL
|| url_scheme (*t) == SCHEME_FTPS
#endif
)
opt.follow_ftp = 1;
retrieve_tree (url_parsed, NULL);
@@ -1682,10 +1864,10 @@ outputting to a regular file.\n"));
opt.follow_ftp = old_follow_ftp;
}
else
{
retrieve_url (url_parsed, *t, &filename, &redirected_URL, NULL,
&dt, opt.recursive, iri, true);
}
{
retrieve_url (url_parsed, *t, &filename, &redirected_URL, NULL,
&dt, opt.recursive, iri, true);
}
if (opt.delete_after && filename != NULL && file_exists_p (filename))
{
@@ -1713,6 +1895,57 @@ outputting to a regular file.\n"));
opt.input_filename);
}
#ifdef HAVE_METALINK
/* Finally, from metlink file, if any. */
if (opt.input_metalink)
{
metalink_error_t meta_err;
uerr_t retr_err;
metalink_t *metalink;
meta_err = metalink_parse_file (opt.input_metalink, &metalink);
if (meta_err)
{
logprintf (LOG_NOTQUIET, _("Unable to parse metalink file %s.\n"),
opt.input_metalink);
retr_err = METALINK_PARSE_ERROR;
}
else
{
/* We need to sort the resources if preferred location
was specified by the user. */
if (opt.preferred_location && opt.preferred_location[0])
{
metalink_file_t **mfile_ptr;
for (mfile_ptr = metalink->files; *mfile_ptr; mfile_ptr++)
{
metalink_resource_t **mres_ptr;
metalink_file_t *mfile = *mfile_ptr;
size_t mres_count = 0;
for (mres_ptr = mfile->resources; *mres_ptr; mres_ptr++)
mres_count++;
stable_sort (mfile->resources,
mres_count,
sizeof (metalink_resource_t *),
metalink_res_cmp);
}
}
retr_err = retrieve_from_metalink (metalink);
if (retr_err != RETROK)
{
logprintf (LOG_NOTQUIET,
_("Could not download all resources from %s.\n"),
quote (opt.input_metalink));
}
metalink_delete (metalink);
}
inform_exit_status (retr_err);
}
#endif /* HAVE_METALINK */
/* Print broken links. */
if (opt.recursive && opt.spider)
print_broken_links ();
@@ -1752,7 +1985,12 @@ outputting to a regular file.\n"));
if (opt.cookies_output)
save_cookies ();
if (opt.convert_links && !opt.delete_after)
#ifdef HAVE_HSTS
if (opt.hsts && hsts_store)
save_hsts ();
#endif
if ((opt.convert_links || opt.convert_file_only) && !opt.delete_after)
convert_all_links ();
cleanup ();

785
src/metalink.c Normal file
View File

@@ -0,0 +1,785 @@
/* Metalink module.
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
GNU Wget 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.
GNU Wget 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. */
#include "wget.h"
#ifdef HAVE_METALINK
#include "metalink.h"
#include "retr.h"
#include "exits.h"
#include "utils.h"
#include "sha256.h"
#include "xstrndup.h"
#include <errno.h>
#include <unistd.h> /* For unlink. */
#include <metalink/metalink_parser.h>
#ifdef HAVE_GPGME
#include <gpgme.h>
#include <fcntl.h> /* For open and close. */
#endif
#ifdef TESTING
#include "test.h"
#endif
/* Loop through all files in metalink structure and retrieve them.
Returns RETROK if all files were downloaded.
Returns last retrieval error (from retrieve_url) if some files
could not be downloaded. */
uerr_t
retrieve_from_metalink (const metalink_t* metalink)
{
metalink_file_t **mfile_ptr;
uerr_t last_retr_err = RETROK; /* Store last encountered retrieve error. */
FILE *_output_stream = output_stream;
bool _output_stream_regular = output_stream_regular;
char *_output_document = opt.output_document;
DEBUGP (("Retrieving from Metalink\n"));
/* No files to download. */
if (!metalink->files)
return RETROK;
if (opt.output_document)
{
/* We cannot support output_document as we need to compute checksum
of downloaded file, and to remove it if the checksum is bad. */
logputs (LOG_NOTQUIET,
_("-O not supported for metalink download. Ignoring.\n"));
}
for (mfile_ptr = metalink->files; *mfile_ptr; mfile_ptr++)
{
metalink_file_t *mfile = *mfile_ptr;
metalink_resource_t **mres_ptr;
char *filename = NULL;
bool hash_ok = false;
uerr_t retr_err = METALINK_MISSING_RESOURCE;
/* -1 -> file should be rejected
0 -> could not verify
1 -> verified successfully */
char sig_status = 0;
output_stream = NULL;
DEBUGP (("Processing metalink file %s...\n", quote (mfile->name)));
/* Resources are sorted by priority. */
for (mres_ptr = mfile->resources; *mres_ptr; mres_ptr++)
{
metalink_resource_t *mres = *mres_ptr;
metalink_checksum_t **mchksum_ptr, *mchksum;
struct iri *iri;
struct url *url;
int url_err;
if (!RES_TYPE_SUPPORTED (mres->type))
{
logprintf (LOG_VERBOSE,
_("Resource type %s not supported, ignoring...\n"),
quote (mres->type));
continue;
}
retr_err = METALINK_RETR_ERROR;
/* If output_stream is not NULL, then we have failed on
previous resource and are retrying. Thus, remove the file. */
if (output_stream)
{
fclose (output_stream);
output_stream = NULL;
if (unlink (filename))
logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
xfree (filename);
}
/* Parse our resource URL. */
iri = iri_new ();
set_uri_encoding (iri, opt.locale, true);
url = url_parse (mres->url, &url_err, iri, false);
if (!url)
{
char *error = url_error (mres->url, url_err);
logprintf (LOG_NOTQUIET, "%s: %s.\n", mres->url, error);
xfree (error);
inform_exit_status (URLERROR);
iri_free (iri);
continue;
}
else
{
/* Avoid recursive Metalink from HTTP headers. */
bool _metalink_http = opt.metalink_over_http;
/* Assure proper local file name regardless of the URL
of particular Metalink resource.
To do that we create the local file here and put
it as output_stream. We restore the original configuration
after we are finished with the file. */
output_stream = unique_create (mfile->name, true, &filename);
output_stream_regular = true;
/* Store the real file name for displaying in messages. */
opt.output_document = filename;
opt.metalink_over_http = false;
DEBUGP (("Storing to %s\n", filename));
retr_err = retrieve_url (url, mres->url, NULL, NULL,
NULL, NULL, opt.recursive, iri, false);
opt.metalink_over_http = _metalink_http;
}
url_free (url);
iri_free (iri);
if (retr_err == RETROK)
{
FILE *local_file;
/* Check the digest. */
local_file = fopen (filename, "rb");
if (!local_file)
{
logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n"));
continue;
}
for (mchksum_ptr = mfile->checksums; *mchksum_ptr; mchksum_ptr++)
{
char sha256[SHA256_DIGEST_SIZE];
char sha256_txt[2 * SHA256_DIGEST_SIZE + 1];
mchksum = *mchksum_ptr;
/* I have seen both variants... */
if (strcasecmp (mchksum->type, "sha256")
&& strcasecmp (mchksum->type, "sha-256"))
{
DEBUGP (("Ignoring unsupported checksum type %s.\n",
quote (mchksum->type)));
continue;
}
logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"),
quote (mfile->name));
sha256_stream (local_file, sha256);
wg_hex_to_string (sha256_txt, sha256, SHA256_DIGEST_SIZE);
DEBUGP (("Declared hash: %s\n", mchksum->hash));
DEBUGP (("Computed hash: %s\n", sha256_txt));
if (!strcmp (sha256_txt, mchksum->hash))
{
logputs (LOG_VERBOSE,
_("Checksum matches.\n"));
hash_ok = true;
}
else
{
logprintf (LOG_NOTQUIET,
_("Checksum mismatch for file %s.\n"),
quote (mfile->name));
hash_ok = false;
}
/* Stop as soon as we checked the supported checksum. */
break;
} /* Iterate over available checksums. */
fclose (local_file);
local_file = NULL;
if (!hash_ok)
continue;
sig_status = 0; /* Not verified. */
#ifdef HAVE_GPGME
/* Check the crypto signature.
Note that the signtures from Metalink in XML will not be
parsed when using libmetalink version older than 0.1.3.
Metalink-over-HTTP is not affected by this problem. */
if (mfile->signature)
{
metalink_signature_t *msig = mfile->signature;
gpgme_error_t gpgerr;
gpgme_ctx_t gpgctx;
gpgme_data_t gpgsigdata, gpgdata;
gpgme_verify_result_t gpgres;
gpgme_signature_t gpgsig;
gpgme_protocol_t gpgprot = GPGME_PROTOCOL_UNKNOWN;
int fd = -1;
/* Initialize the library - as name suggests. */
gpgme_check_version (NULL);
/* Open data file. */
fd = open (filename, O_RDONLY);
if (fd == -1)
{
logputs (LOG_NOTQUIET,
_("Could not open downloaded file for signature "
"verification.\n"));
goto gpg_skip_verification;
}
/* Assign file descriptor to GPG data structure. */
gpgerr = gpgme_data_new_from_fd (&gpgdata, fd);
if (gpgerr != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
"GPGME data_new_from_fd: %s\n",
gpgme_strerror (gpgerr));
goto gpg_skip_verification;
}
/* Prepare new GPGME context. */
gpgerr = gpgme_new (&gpgctx);
if (gpgerr != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
"GPGME new: %s\n",
gpgme_strerror (gpgerr));
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
DEBUGP (("Veryfying signature %s:\n%s\n",
quote (msig->mediatype),
msig->signature));
/* Check signature type. */
if (!strcmp (msig->mediatype, "application/pgp-signature"))
gpgprot = GPGME_PROTOCOL_OpenPGP;
else /* Unsupported signature type. */
{
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
gpgerr = gpgme_set_protocol (gpgctx, gpgprot);
if (gpgerr != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
"GPGME set_protocol: %s\n",
gpgme_strerror (gpgerr));
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
/* Load the signature. */
gpgerr = gpgme_data_new_from_mem (&gpgsigdata,
msig->signature,
strlen (msig->signature),
0);
if (gpgerr != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
_("GPGME data_new_from_mem: %s\n"),
gpgme_strerror (gpgerr));
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
/* Verify the signature. */
gpgerr = gpgme_op_verify (gpgctx, gpgsigdata, gpgdata, NULL);
if (gpgerr != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
_("GPGME op_verify: %s\n"),
gpgme_strerror (gpgerr));
gpgme_data_release (gpgsigdata);
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
/* Check the results. */
gpgres = gpgme_op_verify_result (gpgctx);
if (!gpgres)
{
logputs (LOG_NOTQUIET,
_("GPGME op_verify_result: NULL\n"));
gpgme_data_release (gpgsigdata);
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
goto gpg_skip_verification;
}
/* The list is null-terminated. */
for (gpgsig = gpgres->signatures; gpgsig; gpgsig = gpgsig->next)
{
DEBUGP (("Checking signature 0x%p\n",
(void *) gpgsig));
DEBUGP (("Summary=0x%x Status=0x%x\n",
gpgsig->summary, gpgsig->status & 0xFFFF));
if (gpgsig->summary
& (GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN))
{
logputs (LOG_VERBOSE,
_("Signature validation suceeded.\n"));
sig_status = 1;
break;
}
if (gpgsig->summary & GPGME_SIGSUM_RED)
{
logputs (LOG_NOTQUIET,
_("Invalid signature. Rejecting resource.\n"));
sig_status = -1;
break;
}
if (gpgsig->summary == 0
&& (gpgsig->status & 0xFFFF) == GPG_ERR_NO_ERROR)
{
logputs (LOG_VERBOSE,
_("Data matches signature, but signature "
"is not trusted.\n"));
}
if ((gpgsig->status & 0xFFFF) != GPG_ERR_NO_ERROR)
{
logprintf (LOG_NOTQUIET,
"GPGME: %s\n",
gpgme_strerror (gpgsig->status & 0xFFFF));
}
}
gpgme_data_release (gpgsigdata);
gpgme_release (gpgctx);
gpgme_data_release (gpgdata);
gpg_skip_verification:
if (fd != -1)
close (fd);
} /* endif (mfile->signature) */
#endif
/* Stop if file was downloaded with success. */
if (sig_status >= 0)
break;
} /* endif RETR_OK. */
} /* Iterate over resources. */
if (retr_err != RETROK)
{
logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"),
quote (mfile->name));
}
else if (!hash_ok)
{
retr_err = METALINK_CHKSUM_ERROR;
logprintf (LOG_NOTQUIET,
_("File %s retrieved but checksum does not match. "
"\n"), quote (mfile->name));
}
#ifdef HAVE_GPGME
/* Signature will be only validated if hash check was successful. */
else if (sig_status < 0)
{
retr_err = METALINK_SIG_ERROR;
logprintf (LOG_NOTQUIET,
_("File %s retrieved but signature does not match. "
"\n"), quote (mfile->name));
}
#endif
last_retr_err = retr_err == RETROK ? last_retr_err : retr_err;
/* Remove the file if error encountered or if option specified.
Note: the file has been downloaded using *_loop. Therefore, it
is not necessary to keep the file for continuated download. */
if ((retr_err != RETROK || opt.delete_after)
&& filename != NULL && file_exists_p (filename))
{
logprintf (LOG_VERBOSE, _("Removing %s.\n"), quote (filename));
if (unlink (filename))
logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
}
if (output_stream)
{
fclose (output_stream);
output_stream = NULL;
}
xfree (filename);
} /* Iterate over files. */
/* Restore original values. */
opt.output_document = _output_document;
output_stream_regular = _output_stream_regular;
output_stream = _output_stream;
return last_retr_err;
}
int metalink_res_cmp (const void* v1, const void* v2)
{
const metalink_resource_t *res1 = *(metalink_resource_t **) v1,
*res2 = *(metalink_resource_t **) v2;
if (res1->preference != res2->preference)
return res2->preference - res1->preference;
if (res1->priority != res2->priority)
return res1->priority - res2->priority;
if (opt.preferred_location)
{
int cmp = 0;
if (res1->location &&
!strcasecmp (opt.preferred_location, res1->location))
cmp -= 1;
if (res2->location &&
!strcasecmp (opt.preferred_location, res2->location))
cmp += 1;
return cmp;
}
return 0;
}
/*
Find value of given key. This is intended for Link header, but will
work with any header that uses ';' as field separator and '=' as key-value
separator.
Link = "Link" ":" #link-value
link-value = "<" URI-Reference ">" *( ";" link-param )
link-param = ( ( "rel" "=" relation-types )
| ( "anchor" "=" <"> URI-Reference <"> )
| ( "rev" "=" relation-types )
| ( "hreflang" "=" Language-Tag )
| ( "media" "=" ( MediaDesc | ( <"> MediaDesc <"> ) ) )
| ( "title" "=" quoted-string )
| ( "title*" "=" ext-value )
| ( "type" "=" ( media-type | quoted-mt ) )
| ( link-extension ) )
link-extension = ( parmname [ "=" ( ptoken | quoted-string ) ] )
| ( ext-name-star "=" ext-value )
ext-name-star = parmname "*" ; reserved for RFC2231-profiled
; extensions. Whitespace NOT
; allowed in between.
ptoken = 1*ptokenchar
ptokenchar = "!" | "#" | "$" | "%" | "&" | "'" | "("
| ")" | "*" | "+" | "-" | "." | "/" | DIGIT
| ":" | "<" | "=" | ">" | "?" | "@" | ALPHA
| "[" | "]" | "^" | "_" | "`" | "{" | "|"
| "}" | "~"
media-type = type-name "/" subtype-name
quoted-mt = <"> media-type <">
relation-types = relation-type
| <"> relation-type *( 1*SP relation-type ) <">
relation-type = reg-rel-type | ext-rel-type
reg-rel-type = LOALPHA *( LOALPHA | DIGIT | "." | "-" )
ext-rel-type = URI
See more: rfc5988
*/
bool
find_key_value (const char *start, const char *end, const char *key, char **value)
{
const char *eq;
size_t key_len = strlen (key);
const char *val_beg, *val_end;
const char *key_beg;
key_beg = start;
while (key_beg + key_len + 1 < end)
{
/* Skip whitespaces. */
while (key_beg + key_len + 1 < end && c_isspace (*key_beg))
key_beg++;
if (strncmp (key_beg, key, key_len))
{
/* Find next token. */
while (key_beg + key_len + 1 < end && *key_beg != ';')
key_beg++;
key_beg++;
continue;
}
else
{
/* Find equals sign. */
eq = key_beg + key_len;
while (eq < end && c_isspace (*eq))
eq++;
if (eq == end)
return false;
if (*eq != '=')
{
key_beg++;
continue;
}
val_beg = eq + 1;
while (val_beg < end && c_isspace (*val_beg))
val_beg++;
if (val_beg == end)
return false;
val_end = val_beg + 1;
while (val_end < end && *val_end != ';' && !c_isspace (*val_end))
val_end++;
*value = xstrndup (val_beg, val_end - val_beg);
return true;
}
}
*value = NULL;
return false;
}
/* This is to check if given token exists in HTTP header. Tokens are
separated by ';'. */
bool
has_key (const char *start, const char *end, const char *key)
{
const char *pos; /* Here would the token start. */
size_t key_len = strlen (key);
pos = start;
while (pos + key_len <= end)
{
/* Skip whitespaces at beginning. */
while (pos + key_len <= end && c_isspace (*pos))
pos++;
/* Does the prefix of pos match our key? */
if (strncmp (key, pos, key_len))
{
/* This was not a match.
Skip all characters until beginning of next token. */
while (pos + key_len <= end && *pos != ';')
pos++;
pos++;
continue;
}
/* key is prefix of pos. Is it the exact token or just a prefix? */
pos += key_len;
while (pos < end && c_isspace (*pos))
pos++;
if (pos == end || *pos == ';')
return true;
/* This was not a match (just a prefix).
Skip all characters until beginning of next token. */
while (pos + key_len <= end && *pos != ';')
pos++;
pos++;
}
return false;
}
/* Find all key=value pairs delimited with ';' or ','. This is intended for
Digest header parsing.
The usage is:
const char *pos;
for (pos = header_beg; pos = find_key_values (pos, header_end, &key, &val); pos++)
{
...
}
*/
const char *
find_key_values (const char *start, const char *end, char **key, char **value)
{
const char *key_start, *key_end;
const char *eq;
const char *val_start, *val_end;
eq = start;
while (eq < end && *eq != '=')
{
/* Skip tokens without =value part. */
if (*eq == ';' || *eq == ',')
start = eq + 1;
eq++;
}
if (eq >= end)
return NULL;
key_start = start;
while (key_start < eq && c_isspace (*key_start))
key_start++;
key_end = eq - 1;
while (key_end > key_start && c_isspace (*key_end))
key_end--;
key_end++;
val_start = eq + 1;
while (val_start < end && c_isspace (*val_start))
val_start++;
val_end = val_start;
while (val_end < end && *val_end != ';' &&
*val_end != ',' && !c_isspace (*val_end))
val_end++;
*key = xstrndup (key_start, key_end - key_start);
*value = xstrndup (val_start, val_end - val_start);
/* Skip trailing whitespaces. */
while (val_end < end && c_isspace (*val_end))
val_end++;
return val_end;
}
#ifdef TESTING
const char *
test_find_key_values (void)
{
static const char *header_data = "key1=val1;key2=val2 ;key3=val3; key4=val4"\
" ; key5=val5;key6 =val6;key7= val7; "\
"key8 = val8 ; key9 = val9 "\
" ,key10= val10,key11,key12=val12";
static const struct
{
const char *key;
const char *val;
} test_array[] =
{
{ "key1", "val1" },
{ "key2", "val2" },
{ "key3", "val3" },
{ "key4", "val4" },
{ "key5", "val5" },
{ "key6", "val6" },
{ "key7", "val7" },
{ "key8", "val8" },
{ "key9", "val9" },
{ "key10", "val10" },
{ "key12", "val12" }
};
const char *pos;
char *key, *value;
size_t i = 0;
for (pos = header_data; (pos = find_key_values (pos,
header_data + strlen (header_data),
&key, &value)); pos++)
{
mu_assert ("test_find_key_values: wrong result",
!strcmp (test_array[i].val, value) &&
!strcmp (test_array[i].key, key));
xfree (key);
xfree (value);
i++;
}
return NULL;
}
const char *
test_find_key_value (void)
{
static const char *header_data = "key1=val1;key2=val2 ;key3=val3; key4=val4"\
" ; key5=val5;key6 =val6;key7= val7; "\
"key8 = val8 ; key9 = val9 ";
static const struct
{
const char *key;
const char *val;
bool result;
} test_array[] =
{
{ "key1", "val1", true },
{ "key2", "val2", true },
{ "key3", "val3", true },
{ "key4", "val4", true },
{ "key5", "val5", true },
{ "key6", "val6", true },
{ "key7", "val7", true },
{ "key8", "val8", true },
{ "key9", "val9", true },
{ "key10", NULL, false },
{ "ey1", NULL, false },
{ "dey1", NULL, false }
};
size_t i;
for (i=0; i < countof (test_array); ++i)
{
bool result;
char *value;
result = find_key_value (header_data,
header_data + strlen(header_data),
test_array[i].key, &value);
mu_assert ("test_find_key_value: wrong result",
result == test_array[i].result &&
((!test_array[i].result && !value) ||
!strcmp (value, test_array[i].val)));
xfree (value);
}
return NULL;
}
const char *
test_has_key (void)
{
static const char *header_data = "key1=val2;token1;xyz; token2;xyz;token3 ;"\
"xyz; token4 ;xyz; token5 ";
struct
{
const char *token;
bool result;
} test_array[] =
{
{ "key1=val2", true },
{ "token1", true },
{ "token2", true },
{ "token3", true },
{ "token4", true },
{ "token5", true },
{ "token6", false },
{ "oken1", false },
{ "poken1", false },
{ "key1=val2", true }
};
size_t i;
for (i = 0; i < countof (test_array); ++i)
mu_assert ("test_has_key: wrong result",
has_key (header_data, header_data + strlen (header_data),
test_array[i].token) == test_array[i].result);
return NULL;
}
#endif
#endif /* HAVE_METALINK */

60
src/metalink.h Normal file
View File

@@ -0,0 +1,60 @@
/* Declarations for metalink.c.
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
GNU Wget 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.
GNU Wget 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. */
#if ! defined METALINK_H && defined HAVE_METALINK
#define METALINK_H
#include <metalink/metalink_types.h>
#include "wget.h"
#ifdef HAVE_SSL
# define RES_TYPE_SUPPORTED(x)\
((!x) || !strcmp (x, "http") || !strcmp (x, "https") || !strcmp (x, "ftp") || !strcmp (x, "ftps"))
#else
# define RES_TYPE_SUPPORTED(x)\
((!x) || !strcmp (x, "ftp") || !strcmp (x, "http"))
#endif
#define DEFAULT_PRI 999999
#define VALID_PRI_RANGE(x) ((x) > 0 && (x) < 1000000)
uerr_t retrieve_from_metalink (const metalink_t *metalink);
int metalink_res_cmp (const void *res1, const void *res2);
bool find_key_value (const char *start,
const char *end,
const char *key,
char **value);
bool has_key (const char *start, const char *end, const char *key);
const char *find_key_values (const char *start,
const char *end,
char **key,
char **value);
#endif /* METALINK_H */

View File

@@ -1,7 +1,7 @@
/* mswindows.c -- Windows-specific support
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Declarations for windows
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* Read and parse the .netrc file to get hosts, accounts, and passwords.
Copyright (C) 1996, 2007, 2008, 2009, 2010, 2011 Free Software
Copyright (C) 1996, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Declarations for netrc.c
Copyright (C) 1996, 1996, 1997, 2007, 2008, 2009, 2010, 2011 Free
Software Foundation, Inc.
Copyright (C) 1996, 1996, 1997, 2007, 2008, 2009, 2010, 2011, 2015
Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* SSL support via OpenSSL library.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
2009, 2010, 2011, 2012 Free Software Foundation, Inc.
2009, 2010, 2011, 2012, 2015 Free Software Foundation, Inc.
Originally contributed by Christian Fraenkel.
This file is part of GNU Wget.
@@ -292,10 +292,17 @@ ssl_init (void)
/* Use the private key from the cert file unless otherwise specified. */
if (opt.cert_file && !opt.private_key)
{
opt.private_key = opt.cert_file;
opt.private_key = xstrdup (opt.cert_file);
opt.private_key_type = opt.cert_type;
}
/* Use cert from private key file unless otherwise specified. */
if (opt.private_key && !opt.cert_file)
{
opt.cert_file = xstrdup (opt.private_key);
opt.cert_type = opt.private_key_type;
}
if (opt.cert_file)
if (SSL_CTX_use_certificate_file (ssl_ctx, opt.cert_file,
key_type_to_ssl_type (opt.cert_type))
@@ -327,6 +334,7 @@ ssl_init (void)
struct openssl_transport_context
{
SSL *conn; /* SSL connection handle */
SSL_SESSION *sess; /* SSL session info */
char *last_error; /* last error printed with openssl_errstr */
};
@@ -507,7 +515,7 @@ ssl_connect_with_timeout_callback(void *arg)
Returns true on success, false on failure. */
bool
ssl_connect_wget (int fd, const char *hostname)
ssl_connect_wget (int fd, const char *hostname, int *continue_session)
{
SSL *conn;
struct scwt_context scwt_ctx;
@@ -520,7 +528,7 @@ ssl_connect_wget (int fd, const char *hostname)
if (!conn)
goto error;
#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
/* If the SSL library was build with support for ServerNameIndication
/* If the SSL library was built with support for ServerNameIndication
then use it whenever we have a hostname. If not, don't, ever. */
if (! is_valid_ip_address (hostname))
{
@@ -532,6 +540,14 @@ ssl_connect_wget (int fd, const char *hostname)
}
#endif
if (continue_session)
{
/* attempt to resume a previous SSL session */
ctx = (struct openssl_transport_context *) fd_transport_context (*continue_session);
if (!ctx || !ctx->sess || !SSL_set_session (conn, ctx->sess))
goto error;
}
#ifndef FD_TO_SOCKET
# define FD_TO_SOCKET(X) (X)
#endif
@@ -550,6 +566,9 @@ ssl_connect_wget (int fd, const char *hostname)
ctx = xnew0 (struct openssl_transport_context);
ctx->conn = conn;
ctx->sess = SSL_get0_session (conn);
if (!ctx->sess)
logprintf (LOG_NOTQUIET, "WARNING: Could not save SSL session data for socket %d\n", fd);
/* Register FD with Wget's transport layer, i.e. arrange that our
functions are used for reading, writing, and polling. */
@@ -663,6 +682,10 @@ ssl_check_certificate (int fd, const char *host)
SSL *conn = ctx->conn;
assert (conn != NULL);
/* The user explicitly said to not check for the certificate. */
if (opt.check_cert == CHECK_CERT_QUIET)
return success;
cert = SSL_get_peer_certificate (conn);
if (!cert)
{
@@ -861,13 +884,12 @@ ssl_check_certificate (int fd, const char *host)
X509_free (cert);
no_cert:
if (opt.check_cert && !success)
if (opt.check_cert == CHECK_CERT_ON && !success)
logprintf (LOG_NOTQUIET, _("\
To connect to %s insecurely, use `--no-check-certificate'.\n"),
quotearg_style (escape_quoting_style, host));
/* Allow --no-check-cert to disable certificate checking. */
return opt.check_cert ? success : true;
return opt.check_cert == CHECK_CERT_ON ? success : true;
}
/*

View File

@@ -1,7 +1,7 @@
/* struct options.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -29,6 +29,13 @@ 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. */
enum CHECK_CERT_MODES
{
CHECK_CERT_OFF,
CHECK_CERT_ON,
CHECK_CERT_QUIET
};
struct options
{
int verbose; /* Are we verbose? (First set to -1,
@@ -58,6 +65,11 @@ struct options
char *dir_prefix; /* The top of directory tree */
char *lfilename; /* Log filename */
char *input_filename; /* Input filename */
#ifdef HAVE_METALINK
char *input_metalink; /* Input metalink file */
bool metalink_over_http; /* Use Metalink if present in HTTP response */
char *preferred_location; /* Preferred location for Metalink resources */
#endif
char *choose_config; /* Specified config file */
bool noconfig; /* Ignore all config files? */
bool force_html; /* Is the input file an HTML file? */
@@ -165,6 +177,7 @@ struct options
#endif
bool timestamping; /* Whether to use time-stamping. */
bool if_modified_since; /* Whether to use conditional get requests. */
bool backup_converted; /* Do we save pre-converted files as *.orig? */
int backups; /* Are numeric backups made? */
@@ -176,6 +189,9 @@ struct options
NULL. */
bool convert_links; /* Will the links be converted
locally? */
bool convert_file_only; /* Convert only the file portion of the URI (i.e. basename).
Leave everything else untouched. */
bool remove_listing; /* Do we remove .listing files
generated by FTP? */
bool htmlify; /* Do we HTML-ify the OS-dependent
@@ -206,7 +222,7 @@ struct options
secure_protocol_tlsv1_2,
secure_protocol_pfs
} secure_protocol; /* type of secure protocol to use. */
bool check_cert; /* whether to validate the server's cert */
int check_cert; /* whether to validate the server's cert */
char *cert_file; /* external client certificate to use. */
char *private_key; /* private key file (if not internal). */
enum keyfile_type {
@@ -223,6 +239,10 @@ struct options
char *random_file; /* file with random data to seed the PRNG */
char *egd_file; /* file name of the egd daemon socket */
bool https_only; /* whether to follow HTTPS only */
bool ftps_resume_ssl;
bool ftps_fallback_to_ftp;
bool ftps_implicit;
bool ftps_clear_data_connection;
#endif /* HAVE_SSL */
bool cookies; /* whether cookies are used. */
@@ -239,6 +259,7 @@ struct options
enum {
restrict_unix,
restrict_vms,
restrict_windows
} restrict_files_os; /* file name restriction ruleset. */
bool restrict_files_ctrl; /* non-zero if control chars in URLs
@@ -288,6 +309,13 @@ struct options
bool show_all_dns_entries; /* Show all the DNS entries when resolving a
name. */
bool report_bps; /*Output bandwidth in bits format*/
char *rejected_log; /* The file to log rejected URLS to. */
#ifdef HAVE_HSTS
bool hsts;
char *hsts_file;
#endif
};
extern struct options opt;

View File

@@ -1,6 +1,6 @@
/* Download progress.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011 Free Software Foundation, Inc.
2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
@@ -594,7 +594,8 @@ bar_create (const char *f_download, wgint initial, wgint total)
bp->width = screen_width - 1;
/* + enough space for the terminating zero, and hopefully enough room
* for multibyte characters. */
bp->buffer = xmalloc (bp->width + 100);
#define BUF_LEN (bp->width + 100)
bp->buffer = xmalloc (BUF_LEN);
logputs (LOG_VERBOSE, "\n");
@@ -693,7 +694,7 @@ bar_finish (void *progress, double dltime)
The idea is that for fast downloads, we get the speed over exactly
the last three seconds. For slow downloads (where a network read
takes more than 150ms to complete), we get the speed over a larger
time period, as large as it takes to complete thirty reads. This
time period, as large as it takes to complete twenty reads. This
is good because slow downloads tend to fluctuate more and a
3-second average would be too erratic. */
@@ -854,7 +855,7 @@ get_eta (int *bcd)
{
/* TRANSLATORS: "ETA" is English-centric, but this must
be short, ideally 3 chars. Abbreviate if necessary. */
static const char eta_str[] = N_(" eta %s");
static const char eta_str[] = N_(" eta %s");
static const char *eta_trans;
static int bytes_cols_diff;
if (eta_trans == NULL)
@@ -903,11 +904,11 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
char *p = bp->buffer;
wgint size = bp->initial_length + bp->count;
int size_grouped_pad; /* Used to pad the field width for size_grouped. */
struct bar_progress_hist *hist = &bp->hist;
int orig_filename_cols = count_cols (bp->f_download);
int padding;
/* The progress bar should look like this:
file xx% [=======> ] nnn.nnK 12.34KB/s eta 36m 51s
@@ -928,12 +929,16 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
"=====>..." - progress bar - the rest
*/
/* TODO: Ask the Turkish Translators to fix their translation for the "done"
* mode of progress bar. Use one less character. Once that is done, redice
* PROGRESS_ETA_LEN by 1.
*/
#define PROGRESS_FILENAME_LEN MAX_FILENAME_COLS + 1
#define PROGRESS_PERCENT_LEN 4
#define PROGRESS_DECORAT_LEN 2
#define PROGRESS_FILESIZE_LEN 7 + 1
#define PROGRESS_DWNLOAD_RATE 8 + 1
#define PROGRESS_ETA_LEN 14
#define PROGRESS_DWNLOAD_RATE 8 + 2
#define PROGRESS_ETA_LEN 15
int progress_size = bp->width - (PROGRESS_FILENAME_LEN + PROGRESS_PERCENT_LEN +
PROGRESS_DECORAT_LEN + PROGRESS_FILESIZE_LEN +
@@ -945,41 +950,55 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
int cols_diff;
const char *down_size;
memset (bp->buffer, '\0', BUF_LEN);
if (progress_size < 5)
progress_size = 0;
if (orig_filename_cols <= MAX_FILENAME_COLS)
{
int padding = MAX_FILENAME_COLS - orig_filename_cols;
sprintf (p, "%s ", bp->f_download);
p += orig_filename_cols + 1;
for (;padding;padding--)
*p++ = ' ';
padding = MAX_FILENAME_COLS - orig_filename_cols;
p += sprintf (p, "%s ", bp->f_download);
memset (p, ' ', padding);
p += padding;
}
else
{
int offset_cols;
int bytes_in_filename, offset_bytes, col;
int *cols_ret = &col;
int padding;
#define MIN_SCROLL_TEXT 5
if ((orig_filename_cols > MAX_FILENAME_COLS + MIN_SCROLL_TEXT) &&
!opt.noscroll &&
!done)
offset_cols = ((int) bp->tick) % (orig_filename_cols - MAX_FILENAME_COLS + 1);
{
offset_cols = ((int) bp->tick + orig_filename_cols + MAX_FILENAME_COLS / 2)
% (orig_filename_cols + MAX_FILENAME_COLS);
if (offset_cols > orig_filename_cols)
{
padding = MAX_FILENAME_COLS - (offset_cols - orig_filename_cols);
memset(p, ' ', padding);
p += padding;
offset_cols = 0;
}
else
padding = 0;
}
else
offset_cols = 0;
{
padding = 0;
offset_cols = 0;
}
offset_bytes = cols_to_bytes (bp->f_download, offset_cols, cols_ret);
bytes_in_filename = cols_to_bytes (bp->f_download + offset_bytes,
MAX_FILENAME_COLS,
MAX_FILENAME_COLS - padding,
cols_ret);
memcpy (p, bp->f_download + offset_bytes, bytes_in_filename);
p += bytes_in_filename;
padding = MAX_FILENAME_COLS - *cols_ret;
for (;padding;padding--)
*p++ = ' ';
*p++ = ' ';
padding = MAX_FILENAME_COLS - (padding + *cols_ret);
memset (p, ' ', padding + 1);
p += padding + 1;
}
/* "xx% " */
@@ -987,15 +1006,13 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
{
int percentage = 100.0 * size / bp->total_length;
assert (percentage <= 100);
if (percentage < 100)
sprintf (p, "%3d%%", percentage);
else
strcpy (p, "100%");
p += 4;
p += sprintf (p, "%3d%%", percentage);
}
else
APPEND_LITERAL (" ");
{
memset (p, ' ', PROGRESS_PERCENT_LEN);
p += PROGRESS_PERCENT_LEN;
}
/* The progress bar: "[====> ]" or "[++==> ]". */
if (progress_size && bp->total_length > 0)
@@ -1007,7 +1024,6 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
int dlsz = (double)size / bp->total_length * progress_size;
char *begin;
int i;
assert (dlsz <= progress_size);
assert (insz <= dlsz);
@@ -1017,18 +1033,19 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
/* Print the initial portion of the download with '+' chars, the
rest with '=' and one '>'. */
for (i = 0; i < insz; i++)
*p++ = '+';
memset (p, '+', insz);
p += insz;
dlsz -= insz;
if (dlsz > 0)
{
for (i = 0; i < dlsz - 1; i++)
*p++ = '=';
memset (p, '=', dlsz-1);
p += dlsz - 1;
*p++ = '>';
}
while (p - begin < progress_size)
*p++ = ' ';
memset (p, ' ', (progress_size - (p - begin)));
p += (progress_size - (p - begin));
*p++ = ']';
}
else if (progress_size)
@@ -1056,27 +1073,14 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
*p++ = ']';
}
++bp->tick;
++bp->tick;
/* " 234.56M" */
down_size = human_readable (size, 1000, 2);
cols_diff = 7 - count_cols (down_size);
while (cols_diff > 0)
{
*p++=' ';
cols_diff--;
}
sprintf (p, " %s", down_size);
move_to_end (p);
/* Pad with spaces to 7 chars for the size_grouped field;
* couldn't use the field width specifier in sprintf, because
* it counts in bytes, not characters. */
for (size_grouped_pad = PROGRESS_FILESIZE_LEN - 7;
size_grouped_pad > 0;
--size_grouped_pad)
{
*p++ = ' ';
}
cols_diff = PROGRESS_FILESIZE_LEN - count_cols (down_size);
memset (p, ' ', cols_diff);
p += cols_diff;
p += sprintf (p, "%s", down_size);
/* " 12.52Kb/s or 12.52KB/s" */
if (hist->total_time > 0 && hist->total_bytes)
@@ -1089,12 +1093,11 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
wgint dlquant = hist->total_bytes + bp->recent_bytes;
double dltime = hist->total_time + (dl_total_time - bp->recent_start);
double dlspeed = calc_rate (dlquant, dltime, &units);
sprintf (p, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
p += sprintf (p, " %4.*f%s", dlspeed >= 99.95 ? 0 : dlspeed >= 9.995 ? 1 : 2,
dlspeed, !opt.report_bps ? short_units[units] : short_units_bits[units]);
move_to_end (p);
}
else
APPEND_LITERAL (" --.-KB/s");
APPEND_LITERAL (" --.-KB/s");
if (!done)
{
@@ -1129,14 +1132,14 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
bp->last_eta_time = dl_total_time;
}
sprintf (p, get_eta(&bytes_cols_diff),
p += sprintf (p, get_eta(&bytes_cols_diff),
eta_to_human_short (eta, false));
move_to_end (p);
}
else if (bp->total_length > 0)
{
skip_eta:
APPEND_LITERAL (" ");
memset (p, ' ', PROGRESS_ETA_LEN);
p += PROGRESS_ETA_LEN;
}
}
else
@@ -1146,21 +1149,23 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
int ncols;
/* Note to translators: this should not take up more room than
available here. Abbreviate if necessary. */
strcpy (p, _(" in "));
available here (6 columns). Abbreviate if necessary. */
strcpy (p, _(" in "));
nbytes = strlen (p);
ncols = count_cols (p);
bytes_cols_diff = nbytes - ncols;
p += nbytes;
if (dl_total_time >= 10)
strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
ncols += sprintf (p + nbytes, "%s", eta_to_human_short ((int) (dl_total_time + 0.5), false));
else
sprintf (p, "%ss", print_decimal (dl_total_time));
move_to_end (p);
ncols += sprintf (p + nbytes, "%ss", print_decimal (dl_total_time));
p += ncols + bytes_cols_diff;
memset (p, ' ', PROGRESS_ETA_LEN - ncols);
p += PROGRESS_ETA_LEN - ncols;
}
while (p - bp->buffer - bytes_cols_diff < bp->width)
*p++ = ' ';
padding = bp->width - count_cols (bp->buffer);
memset (p, ' ', padding);
p += padding;
*p = '\0';
/* 2014-11-14 Darshit Shah <darnir@gmail.com>
@@ -1170,7 +1175,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
* assertion fails. Instead Wget should continue downloading and display a
* horrible and irritating progress bar that spams the screen with newlines.
*/
assert (count_cols (bp->buffer) <= bp->width + 1);
assert (count_cols (bp->buffer) == bp->width);
}
/* Print the contents of the buffer as a one-line ASCII "image" so

View File

@@ -1,6 +1,6 @@
/* Download progress.
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010, 2011 Free Software Foundation, Inc.
2010, 2011, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Portable timers.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Declarations for ptimer.c.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,7 +1,7 @@
/* Handling of recursive HTTP retrieving.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -50,6 +50,7 @@ as that of the covered work. */
#include "html-url.h"
#include "css-url.h"
#include "spider.h"
#include "exits.h"
/* Functions for maintaining the URL queue. */
@@ -181,11 +182,20 @@ static int blacklist_contains (struct hash_table *blacklist, const char *url)
return ret;
}
static bool download_child_p (const struct urlpos *, struct url *, int,
struct url *, struct hash_table *, struct iri *);
static bool descend_redirect_p (const char *, struct url *, int,
struct url *, struct hash_table *, struct iri *);
typedef enum
{
WG_RR_SUCCESS, WG_RR_BLACKLIST, WG_RR_NOTHTTPS, WG_RR_NONHTTP, WG_RR_ABSOLUTE,
WG_RR_DOMAIN, WG_RR_PARENT, WG_RR_LIST, WG_RR_REGEX, WG_RR_RULES,
WG_RR_SPANNEDHOST, WG_RR_ROBOTS
} reject_reason;
static reject_reason download_child (const struct urlpos *, struct url *, int,
struct url *, struct hash_table *, struct iri *);
static reject_reason descend_redirect (const char *, struct url *, int,
struct url *, struct hash_table *, struct iri *);
static void write_reject_log_header (FILE *);
static void write_reject_log_reason (FILE *, reject_reason,
const struct url *, const struct url *);
/* Retrieve a part of the web beginning with START_URL. This used to
be called "recursive retrieval", because the old function was
@@ -222,6 +232,8 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
struct iri *i = iri_new ();
FILE *rejectedlog = NULL; /* Don't write a rejected log. */
#define COPYSTR(x) (x) ? xstrdup(x) : NULL;
/* Duplicate pi struct if not NULL */
if (pi)
@@ -243,6 +255,14 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
false);
blacklist_add (blacklist, start_url_parsed->url);
if (opt.rejected_log)
{
rejectedlog = fopen (opt.rejected_log, "w");
write_reject_log_header (rejectedlog);
if (!rejectedlog)
logprintf (LOG_NOTQUIET, "%s: %s\n", opt.rejected_log, strerror (errno));
}
while (1)
{
bool descend = false;
@@ -265,9 +285,9 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
break;
/* ...and download it. Note that this download is in most cases
unconditional, as download_child_p already makes sure a file
unconditional, as download_child already makes sure a file
doesn't get enqueued twice -- and yet this check is here, and
not in download_child_p. This is so that if you run `wget -r
not in download_child. This is so that if you run `wget -r
URL1 URL2', and a random URL is encountered once under URL1
and again under URL2, but at a different (possibly smaller)
depth, we want the URL's children to be taken into account
@@ -298,52 +318,69 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
char *redirected = NULL;
struct url *url_parsed = url_parse (url, &url_err, i, true);
status = retrieve_url (url_parsed, url, &file, &redirected, referer,
&dt, false, i, true);
if (html_allowed && file && status == RETROK
&& (dt & RETROKF) && (dt & TEXTHTML))
if (!url_parsed)
{
descend = true;
is_css = false;
}
/* a little different, css_allowed can override content type
lots of web servers serve css with an incorrect content type
*/
if (file && status == RETROK
&& (dt & RETROKF) &&
((dt & TEXTCSS) || css_allowed))
{
descend = true;
is_css = true;
}
if (redirected)
{
/* We have been redirected, possibly to another host, or
different path, or wherever. Check whether we really
want to follow it. */
if (descend)
{
if (!descend_redirect_p (redirected, url_parsed, depth,
start_url_parsed, blacklist, i))
descend = false;
else
/* Make sure that the old pre-redirect form gets
blacklisted. */
blacklist_add (blacklist, url);
}
xfree (url);
url = redirected;
char *error = url_error (url, url_err);
logprintf (LOG_NOTQUIET, "%s: %s.\n",url, error);
xfree (error);
inform_exit_status (URLERROR);
}
else
{
xfree (url);
url = xstrdup (url_parsed->url);
status = retrieve_url (url_parsed, url, &file, &redirected, referer,
&dt, false, i, true);
if (html_allowed && file && status == RETROK
&& (dt & RETROKF) && (dt & TEXTHTML))
{
descend = true;
is_css = false;
}
/* a little different, css_allowed can override content type
lots of web servers serve css with an incorrect content type
*/
if (file && status == RETROK
&& (dt & RETROKF) &&
((dt & TEXTCSS) || css_allowed))
{
descend = true;
is_css = true;
}
if (redirected)
{
/* We have been redirected, possibly to another host, or
different path, or wherever. Check whether we really
want to follow it. */
if (descend)
{
reject_reason r = descend_redirect (redirected, url_parsed,
depth, start_url_parsed, blacklist, i);
if (r == WG_RR_SUCCESS)
{
/* Make sure that the old pre-redirect form gets
blacklisted. */
blacklist_add (blacklist, url);
}
else
{
write_reject_log_reason (rejectedlog, r, url_parsed, start_url_parsed);
descend = false;
}
}
xfree (url);
url = redirected;
}
else
{
xfree (url);
url = xstrdup (url_parsed->url);
}
url_free (url_parsed);
}
url_free (url_parsed);
}
if (opt.spider)
@@ -409,12 +446,16 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
for (; child; child = child->next)
{
reject_reason r;
if (child->ignore_when_downloading)
continue;
if (dash_p_leaf_HTML && !child->link_inline_p)
continue;
if (download_child_p (child, url_parsed, depth, start_url_parsed,
blacklist, i))
r = download_child (child, url_parsed, depth,
start_url_parsed, blacklist, i);
if (r == WG_RR_SUCCESS)
{
ci = iri_new ();
set_uri_encoding (ci, i->content_encoding, false);
@@ -427,6 +468,10 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
same URL twice. */
blacklist_add (blacklist, child->url->url);
}
else
{
write_reject_log_reason (rejectedlog, r, child->url, url_parsed);
}
}
if (strip_auth)
@@ -466,6 +511,9 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
iri_free (i);
}
if (rejectedlog)
fclose (rejectedlog);
/* If anything is left of the queue due to a premature exit, free it
now. */
{
@@ -501,14 +549,15 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
by storing these URLs to BLACKLIST. This may or may not help. It
will help if those URLs are encountered many times. */
static bool
download_child_p (const struct urlpos *upos, struct url *parent, int depth,
static reject_reason
download_child (const struct urlpos *upos, struct url *parent, int depth,
struct url *start_url_parsed, struct hash_table *blacklist,
struct iri *iri)
{
struct url *u = upos->url;
const char *url = u->url;
bool u_scheme_like_http;
reject_reason reason = WG_RR_SUCCESS;
DEBUGP (("Deciding whether to enqueue \"%s\".\n", url));
@@ -517,11 +566,12 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
if (opt.spider)
{
char *referrer = url_string (parent, URL_AUTH_HIDE_PASSWD);
DEBUGP (("download_child_p: parent->url is: %s\n", quote (parent->url)));
DEBUGP (("download_child: parent->url is: %s\n", quote (parent->url)));
visited_url (url, referrer);
xfree (referrer);
}
DEBUGP (("Already on the black list.\n"));
reason = WG_RR_BLACKLIST;
goto out;
}
@@ -551,6 +601,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
if (opt.https_only && u->scheme != SCHEME_HTTPS)
{
DEBUGP (("Not following non-HTTPS links.\n"));
reason = WG_RR_NOTHTTPS;
goto out;
}
#endif
@@ -559,9 +610,14 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
u_scheme_like_http = schemes_are_similar_p (u->scheme, SCHEME_HTTP);
/* 1. Schemes other than HTTP are normally not recursed into. */
if (!u_scheme_like_http && !(u->scheme == SCHEME_FTP && opt.follow_ftp))
if (!u_scheme_like_http && !((u->scheme == SCHEME_FTP
#ifdef HAVE_SSL
|| u->scheme == SCHEME_FTPS
#endif
) && opt.follow_ftp))
{
DEBUGP (("Not following non-HTTP schemes.\n"));
reason = WG_RR_NONHTTP;
goto out;
}
@@ -571,6 +627,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
if (opt.relative_only && !upos->link_relative_p)
{
DEBUGP (("It doesn't really look like a relative link.\n"));
reason = WG_RR_ABSOLUTE;
goto out;
}
@@ -579,6 +636,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
if (!accept_domain (u))
{
DEBUGP (("The domain was not accepted.\n"));
reason = WG_RR_DOMAIN;
goto out;
}
@@ -598,6 +656,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
{
DEBUGP (("Going to \"%s\" would escape \"%s\" with no_parent on.\n",
u->dir, start_url_parsed->dir));
reason = WG_RR_PARENT;
goto out;
}
}
@@ -610,12 +669,14 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
if (!accdir (u->dir))
{
DEBUGP (("%s (%s) is excluded/not-included.\n", url, u->dir));
reason = WG_RR_LIST;
goto out;
}
}
if (!accept_url (url))
{
DEBUGP (("%s is excluded/not-included through regex.\n", url));
reason = WG_RR_REGEX;
goto out;
}
@@ -640,6 +701,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
{
DEBUGP (("%s (%s) does not match acc/rej rules.\n",
url, u->file));
reason = WG_RR_RULES;
goto out;
}
}
@@ -650,6 +712,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
{
DEBUGP (("This is not the same hostname as the parent's (%s and %s).\n",
u->host, parent->host));
reason = WG_RR_SPANNEDHOST;
goto out;
}
@@ -692,35 +755,36 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
{
DEBUGP (("Not following %s because robots.txt forbids it.\n", url));
blacklist_add (blacklist, url);
reason = WG_RR_ROBOTS;
goto out;
}
}
/* The URL has passed all the tests. It can be placed in the
download queue. */
DEBUGP (("Decided to load it.\n"));
out:
return true;
if (reason == WG_RR_SUCCESS)
/* The URL has passed all the tests. It can be placed in the
download queue. */
DEBUGP (("Decided to load it.\n"));
else
DEBUGP (("Decided NOT to load it.\n"));
out:
DEBUGP (("Decided NOT to load it.\n"));
return false;
return reason;
}
/* This function determines whether we will consider downloading the
children of a URL whose download resulted in a redirection,
possibly to another host, etc. It is needed very rarely, and thus
it is merely a simple-minded wrapper around download_child_p. */
it is merely a simple-minded wrapper around download_child. */
static bool
descend_redirect_p (const char *redirected, struct url *orig_parsed, int depth,
static reject_reason
descend_redirect (const char *redirected, struct url *orig_parsed, int depth,
struct url *start_url_parsed, struct hash_table *blacklist,
struct iri *iri)
{
struct url *new_parsed;
struct urlpos *upos;
bool success;
reject_reason reason;
assert (orig_parsed != NULL);
@@ -730,10 +794,10 @@ descend_redirect_p (const char *redirected, struct url *orig_parsed, int depth,
upos = xnew0 (struct urlpos);
upos->url = new_parsed;
success = download_child_p (upos, orig_parsed, depth,
reason = download_child (upos, orig_parsed, depth,
start_url_parsed, blacklist, iri);
if (success)
if (reason == WG_RR_SUCCESS)
blacklist_add (blacklist, upos->url->url);
else
DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));
@@ -741,7 +805,93 @@ descend_redirect_p (const char *redirected, struct url *orig_parsed, int depth,
url_free (new_parsed);
xfree (upos);
return success;
return reason;
}
/* This function writes the rejected log header. */
static void
write_reject_log_header (FILE *f)
{
if (!f)
return;
/* Note: Update this header when columns change in any way. */
fprintf (f, "REASON\t"
"U_URL\tU_SCHEME\tU_HOST\tU_PORT\tU_PATH\tU_PARAMS\tU_QUERY\tU_FRAGMENT\t"
"P_URL\tP_SCHEME\tP_HOST\tP_PORT\tP_PATH\tP_PARAMS\tP_QUERY\tP_FRAGMENT\n");
}
/* This function writes a URL to the reject log. Internal use only. */
static void
write_reject_log_url (FILE *fp, const struct url *url)
{
const char *escaped_str;
const char *scheme_str;
if (!fp)
return;
escaped_str = url_escape (url->url);
switch (url->scheme)
{
case SCHEME_HTTP: scheme_str = "SCHEME_HTTP"; break;
#ifdef HAVE_SSL
case SCHEME_HTTPS: scheme_str = "SCHEME_HTTPS"; break;
case SCHEME_FTPS: scheme_str = "SCHEME_FTPS"; break;
#endif
case SCHEME_FTP: scheme_str = "SCHEME_FTP"; break;
default: scheme_str = "SCHEME_INVALID"; break;
}
fprintf (fp, "%s\t%s\t%s\t%i\t%s\t%s\t%s\t%s",
escaped_str,
scheme_str,
url->host,
url->port,
url->path,
url->params ? url->params : "",
url->query ? url->query : "",
url->fragment ? url->fragment : "");
xfree (escaped_str);
}
/* This function writes out information on why a URL was rejected and its
context from download_child such as the URL being rejected and it's
parent's URL. The format it uses is comma separated values but with tabs. */
static void
write_reject_log_reason (FILE *fp, reject_reason reason,
const struct url *url, const struct url *parent)
{
const char *reason_str;
if (!fp)
return;
switch (reason)
{
case WG_RR_SUCCESS: reason_str = "SUCCESS"; break;
case WG_RR_BLACKLIST: reason_str = "BLACKLIST"; break;
case WG_RR_NOTHTTPS: reason_str = "NOTHTTPS"; break;
case WG_RR_NONHTTP: reason_str = "NONHTTP"; break;
case WG_RR_ABSOLUTE: reason_str = "ABSOLUTE"; break;
case WG_RR_DOMAIN: reason_str = "DOMAIN"; break;
case WG_RR_PARENT: reason_str = "PARENT"; break;
case WG_RR_LIST: reason_str = "LIST"; break;
case WG_RR_REGEX: reason_str = "REGEX"; break;
case WG_RR_RULES: reason_str = "RULES"; break;
case WG_RR_SPANNEDHOST: reason_str = "SPANNEDHOST"; break;
case WG_RR_ROBOTS: reason_str = "ROBOTS"; break;
default: reason_str = "UNKNOWN"; break;
}
fprintf (fp, "%s\t", reason_str);
write_reject_log_url (fp, url);
fprintf (fp, "\t");
write_reject_log_url (fp, parent);
fprintf (fp, "\n");
}
/* vim:set sts=2 sw=2 cino+={s: */

View File

@@ -1,7 +1,7 @@
/* Declarations for recur.c.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Support for Robot Exclusion Standard (RES).
Copyright (C) 2001, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2001, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of Wget.

View File

@@ -1,5 +1,5 @@
/* Declarations for res.c.
Copyright (C) 2001, 2007, 2008, 2009, 2010, 2011 Free Software
Copyright (C) 2001, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of Wget.

View File

@@ -1,7 +1,7 @@
/* File retrieval.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -56,6 +56,7 @@ as that of the covered work. */
#include "ptimer.h"
#include "html-url.h"
#include "iri.h"
#include "hsts.h"
/* Total size of downloaded files. Used to enforce quota. */
SUM_SIZE_INT total_downloaded_bytes;
@@ -725,7 +726,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
char *mynewloc, *proxy;
struct url *u = orig_parsed, *proxy_url;
int up_error_code; /* url parse error code */
char *local_file;
char *local_file = NULL;
int redirection_count = 0;
bool method_suspended = false;
@@ -753,7 +754,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
result = NOCONERROR;
mynewloc = NULL;
local_file = NULL;
xfree(local_file);
proxy_url = NULL;
proxy = getproxy (u);
@@ -772,6 +773,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
proxy, error);
xfree (url);
xfree (error);
xfree (proxy);
iri_free (pi);
RESTORE_METHOD;
result = PROXERR;
goto bail;
@@ -781,6 +784,8 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
logprintf (LOG_NOTQUIET, _("Error in proxy URL %s: Must be HTTP.\n"), proxy);
url_free (proxy_url);
xfree (url);
xfree (proxy);
iri_free (pi);
RESTORE_METHOD;
result = PROXERR;
goto bail;
@@ -795,10 +800,28 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
#endif
|| (proxy_url && proxy_url->scheme == SCHEME_HTTP))
{
#ifdef HAVE_HSTS
#ifdef TESTING
/* we don't link against main.o when we're testing */
hsts_store_t hsts_store = NULL;
#else
extern hsts_store_t hsts_store;
#endif
if (opt.hsts && hsts_store)
{
if (hsts_match (hsts_store, u))
logprintf (LOG_VERBOSE, "URL transformed to HTTPS due to an HSTS policy\n");
}
#endif
result = http_loop (u, orig_parsed, &mynewloc, &local_file, refurl, dt,
proxy_url, iri);
}
else if (u->scheme == SCHEME_FTP)
else if (u->scheme == SCHEME_FTP
#ifdef HAVE_SSL
|| u->scheme == SCHEME_FTPS
#endif
)
{
/* If this is a redirection, temporarily turn off opt.ftp_glob
and opt.recursive, both being undesirable when following
@@ -814,7 +837,11 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
FTP. In these cases we must decide whether the text is HTML
according to the suffix. The HTML suffixes are `.html',
`.htm' and a few others, case-insensitive. */
if (redirection_count && local_file && u->scheme == SCHEME_FTP)
if (redirection_count && local_file && (u->scheme == SCHEME_FTP
#ifdef HAVE_SSL
|| u->scheme == SCHEME_FTPS
#endif
))
{
if (has_html_suffix_p (local_file))
*dt |= TEXTHTML;
@@ -941,7 +968,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
DEBUGP (("[Couldn't fallback to non-utf8 for %s\n", quote (url)));
}
if (local_file && u && *dt & RETROKF)
if (local_file && u && (*dt & RETROKF || opt.content_on_error))
{
register_download (u->url, local_file);
@@ -984,6 +1011,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
bail:
if (register_status)
inform_exit_status (result);
return result;
}
@@ -1019,6 +1047,7 @@ retrieve_from_file (const char *file, bool html, int *count)
char *error = url_error (url, url_err);
logprintf (LOG_NOTQUIET, "%s: %s.\n", url, error);
xfree (error);
iri_free (iri);
return URLERROR;
}
@@ -1074,12 +1103,20 @@ retrieve_from_file (const char *file, bool html, int *count)
proxy = getproxy (cur_url->url);
if ((opt.recursive || opt.page_requisites)
&& (cur_url->url->scheme != SCHEME_FTP || proxy))
&& ((cur_url->url->scheme != SCHEME_FTP
#ifdef HAVE_SSL
&& cur_url->url->scheme != SCHEME_FTPS
#endif
) || proxy))
{
int old_follow_ftp = opt.follow_ftp;
/* Turn opt.follow_ftp on in case of recursive FTP retrieval */
if (cur_url->url->scheme == SCHEME_FTP)
if (cur_url->url->scheme == SCHEME_FTP
#ifdef HAVE_SSL
|| cur_url->url->scheme == SCHEME_FTPS
#endif
)
opt.follow_ftp = 1;
status = retrieve_tree (parsed_url ? parsed_url : cur_url->url,
@@ -1260,6 +1297,9 @@ getproxy (struct url *u)
case SCHEME_HTTPS:
proxy = opt.https_proxy ? opt.https_proxy : getenv ("https_proxy");
break;
case SCHEME_FTPS:
proxy = opt.ftp_proxy ? opt.ftp_proxy : getenv ("ftps_proxy");
break;
#endif
case SCHEME_FTP:
proxy = opt.ftp_proxy ? opt.ftp_proxy : getenv ("ftp_proxy");

View File

@@ -1,7 +1,7 @@
/* Declarations for retr.c.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* Keep track of visited URLs in spider mode.
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* Declarations for spider.c
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* SSL support.
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
2009, 2010, 2011, 2012 Free Software Foundation, Inc.
2009, 2010, 2011, 2012, 2015 Free Software Foundation, Inc.
Originally contributed by Christian Fraenkel.
This file is part of GNU Wget.
@@ -33,7 +33,7 @@ as that of the covered work. */
#define GEN_SSLFUNC_H
bool ssl_init (void);
bool ssl_connect_wget (int, const char *);
bool ssl_connect_wget (int, const char *, int *);
bool ssl_check_certificate (int, const char *);
#endif /* GEN_SSLFUNC_H */

View File

@@ -1,7 +1,7 @@
/* Dirty system-dependent hacks.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,6 +1,6 @@
/* Unit testing.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -41,24 +41,20 @@ as that of the covered work. */
#error "TESTING not set!!!"
#endif
const char *test_parse_content_disposition(void);
const char *test_subdir_p(void);
const char *test_dir_matches_p(void);
const char *test_commands_sorted(void);
const char *test_cmd_spec_restrict_file_names(void);
const char *test_path_simplify (void);
const char *test_append_uri_pathel(void);
const char *test_are_urls_equal(void);
const char *test_is_robots_txt_url(void);
const char *program_argstring = "TEST";
int tests_run;
static int tests_run;
static const char *
all_tests(void)
{
#ifdef HAVE_METALINK
mu_run_test (test_find_key_value);
mu_run_test (test_find_key_values);
mu_run_test (test_has_key);
#endif
mu_run_test (test_parse_content_disposition);
mu_run_test (test_parse_range_header);
mu_run_test (test_subdir_p);
mu_run_test (test_dir_matches_p);
mu_run_test (test_commands_sorted);
@@ -67,6 +63,12 @@ all_tests(void)
mu_run_test (test_append_uri_pathel);
mu_run_test (test_are_urls_equal);
mu_run_test (test_is_robots_txt_url);
#ifdef HAVE_HSTS
mu_run_test (test_hsts_new_entry);
mu_run_test (test_hsts_url_rewrite_superdomain);
mu_run_test (test_hsts_url_rewrite_congruent);
mu_run_test (test_hsts_read_database);
#endif
return NULL;
}
@@ -78,6 +80,7 @@ main (int argc _GL_UNUSED, const char *argv[])
{
const char *result;
printf ("[DEBUG] Testing...\n\n");
#ifdef ENABLE_NLS
/* Set the current locale. */
setlocale (LC_ALL, "");

View File

@@ -1,6 +1,6 @@
/* Unit testing declarations.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
Foundation, Inc.
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free
Software Foundation, Inc.
This file is part of GNU Wget.
@@ -43,9 +43,12 @@ do { \
puts("PASSED\n"); \
} while (0)
extern int tests_run;
const char *test_has_key (void);
const char *test_find_key_value (void);
const char *test_find_key_values (void);
const char *test_parse_content_disposition(void);
const char *test_parse_range_header(void);
const char *test_commands_sorted(void);
const char *test_cmd_spec_restrict_file_names(void);
const char *test_is_robots_txt_url(void);
@@ -54,6 +57,10 @@ const char *test_append_uri_pathel(void);
const char *test_are_urls_equal(void);
const char *test_subdir_p(void);
const char *test_dir_matches_p(void);
const char *test_hsts_new_entry(void);
const char *test_hsts_url_rewrite_superdomain(void);
const char *test_hsts_url_rewrite_congruent(void);
const char *test_hsts_read_database(void);
#endif /* TEST_H */

121
src/url.c
View File

@@ -1,7 +1,7 @@
/* URL handling.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -78,6 +78,13 @@ static struct scheme_data supported_schemes[] =
{ "https", "https://", DEFAULT_HTTPS_PORT, scm_has_query|scm_has_fragment },
#endif
{ "ftp", "ftp://", DEFAULT_FTP_PORT, scm_has_params|scm_has_fragment },
#ifdef HAVE_SSL
/*
* Explicit FTPS uses the same port as FTP.
* Implicit FTPS has its own port (990), but it is disabled by default.
*/
{ "ftps", "ftps://", DEFAULT_FTP_PORT, scm_has_params|scm_has_fragment },
#endif
/* SCHEME_INVALID */
{ NULL, NULL, -1, 0 }
@@ -161,17 +168,8 @@ static const unsigned char urlchr_table[256] =
#undef U
#undef RU
/* URL-unescape the string S.
This is done by transforming the sequences "%HH" to the character
represented by the hexadecimal digits HH. If % is not followed by
two hexadecimal digits, it is inserted literally.
The transformation is done in place. If you need the original
string intact, make a copy before calling this function. */
void
url_unescape (char *s)
static void
url_unescape_1 (char *s, unsigned char mask)
{
char *t = s; /* t - tortoise */
char *h = s; /* h - hare */
@@ -190,6 +188,8 @@ url_unescape (char *s)
if (!h[1] || !h[2] || !(c_isxdigit (h[1]) && c_isxdigit (h[2])))
goto copychar;
c = X2DIGITS_TO_NUM (h[1], h[2]);
if (urlchr_test(c, mask))
goto copychar;
/* Don't unescape %00 because there is no way to insert it
into a C string without effectively truncating it. */
if (c == '\0')
@@ -201,6 +201,31 @@ url_unescape (char *s)
*t = '\0';
}
/* URL-unescape the string S.
This is done by transforming the sequences "%HH" to the character
represented by the hexadecimal digits HH. If % is not followed by
two hexadecimal digits, it is inserted literally.
The transformation is done in place. If you need the original
string intact, make a copy before calling this function. */
void
url_unescape (char *s)
{
url_unescape_1 (s, 0);
}
/* URL-unescape the string S.
This functions behaves identically as url_unescape(), but does not
convert characters from "reserved". In other words, it only converts
"unsafe" characters. */
void
url_unescape_except_reserved (char *s)
{
url_unescape_1 (s, urlchr_reserved);
}
/* The core of url_escape_* functions. Escapes the characters that
match the provided mask in urlchr_table.
@@ -701,7 +726,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
{
char *new_url = NULL;
iri->utf8_encode = remote_to_utf8 (iri, iri->orig_url ? iri->orig_url : url, (const char **) &new_url);
iri->utf8_encode = remote_to_utf8 (iri, iri->orig_url ? iri->orig_url : url, &new_url);
if (!iri->utf8_encode)
new_url = NULL;
else
@@ -1328,8 +1353,9 @@ append_string (const char *str, struct growable *dest)
enum {
filechr_not_unix = 1, /* unusable on Unix, / and \0 */
filechr_not_windows = 2, /* unusable on Windows, one of \|/<>?:*" */
filechr_control = 4 /* a control character, e.g. 0-31 */
filechr_not_vms = 2, /* unusable on VMS (ODS5), 0x00-0x1F * ? */
filechr_not_windows = 4, /* unusable on Windows, one of \|/<>?:*" */
filechr_control = 8 /* a control character, e.g. 0-31 */
};
#define FILE_CHAR_TEST(c, mask) \
@@ -1338,11 +1364,14 @@ enum {
/* Shorthands for the table: */
#define U filechr_not_unix
#define V filechr_not_vms
#define W filechr_not_windows
#define C filechr_control
#define UVWC U|V|W|C
#define UW U|W
#define UWC U|W|C
#define VC V|C
#define VW V|W
/* Table of characters unsafe under various conditions (see above).
@@ -1353,22 +1382,22 @@ enum {
static const unsigned char filechr_table[256] =
{
UWC, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
C, C, C, C, C, C, C, C, /* BS HT LF VT FF CR SO SI */
C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */
0, 0, W, 0, 0, 0, 0, 0, /* SP ! " # $ % & ' */
0, 0, W, 0, 0, 0, 0, UW, /* ( ) * + , - . / */
0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
0, 0, W, 0, W, 0, W, W, /* 8 9 : ; < = > ? */
0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
0, 0, 0, 0, W, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
0, 0, 0, 0, W, 0, 0, C, /* x y z { | } ~ DEL */
UVWC, VC, VC, VC, VC, VC, VC, VC, /* NUL SOH STX ETX EOT ENQ ACK BEL */
VC, VC, VC, VC, VC, VC, VC, VC, /* BS HT LF VT FF CR SO SI */
VC, VC, VC, VC, VC, VC, VC, VC, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
VC, VC, VC, VC, VC, VC, VC, VC, /* CAN EM SUB ESC FS GS RS US */
0, 0, W, 0, 0, 0, 0, 0, /* SP ! " # $ % & ' */
0, 0, VW, 0, 0, 0, 0, UW, /* ( ) * + , - . / */
0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
0, 0, W, 0, W, 0, W, VW, /* 8 9 : ; < = > ? */
0, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
0, 0, 0, 0, W, 0, 0, 0, /* X Y Z [ \ ] ^ _ */
0, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
0, 0, 0, 0, W, 0, 0, C, /* x y z { | } ~ DEL */
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, /* 128-143 */
C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, /* 144-159 */
@@ -1381,10 +1410,13 @@ UWC, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
#undef U
#undef V
#undef W
#undef C
#undef UW
#undef UWC
#undef UVWC
#undef VC
#undef VW
/* FN_PORT_SEP is the separator between host and port in file names
for non-standard port numbers. On Unix this is normally ':', as in
@@ -1393,10 +1425,14 @@ UWC, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
#define FN_PORT_SEP (opt.restrict_files_os != restrict_windows ? ':' : '+')
/* FN_QUERY_SEP is the separator between the file name and the URL
query, normally '?'. Since Windows cannot handle '?' as part of
query, normally '?'. Because VMS and Windows cannot handle '?' in a
file name, we use '@' instead there. */
#define FN_QUERY_SEP (opt.restrict_files_os != restrict_windows ? '?' : '@')
#define FN_QUERY_SEP_STR (opt.restrict_files_os != restrict_windows ? "?" : "@")
#define FN_QUERY_SEP \
(((opt.restrict_files_os != restrict_vms) && \
(opt.restrict_files_os != restrict_windows)) ? '?' : '@')
#define FN_QUERY_SEP_STR \
(((opt.restrict_files_os != restrict_vms) && \
(opt.restrict_files_os != restrict_windows)) ? "?" : "@")
/* Quote path element, characters in [b, e), as file name, and append
the quoted string to DEST. Each character is quoted as per
@@ -1415,6 +1451,8 @@ append_uri_pathel (const char *b, const char *e, bool escaped,
int mask;
if (opt.restrict_files_os == restrict_unix)
mask = filechr_not_unix;
else if (opt.restrict_files_os == restrict_vms)
mask = filechr_not_vms;
else
mask = filechr_not_windows;
if (opt.restrict_files_ctrl)
@@ -1741,7 +1779,7 @@ path_simplify (enum url_scheme scheme, char *path)
else if (h[0] == '.' && h[1] == '.' && (h[2] == '/' || h[2] == '\0'))
{
/* Handle "../" by retreating the tortoise by one path
element -- but not past beggining. */
element -- but not past beginning. */
if (t > beg)
{
/* Move backwards until T hits the beginning of the
@@ -1749,7 +1787,11 @@ path_simplify (enum url_scheme scheme, char *path)
for (--t; t > beg && t[-1] != '/'; t--)
;
}
else if (scheme == SCHEME_FTP)
else if (scheme == SCHEME_FTP
#ifdef HAVE_SSL
|| scheme == SCHEME_FTPS
#endif
)
{
/* If we're at the beginning, copy the "../" literally
and move the beginning so a later ".." doesn't remove
@@ -2319,6 +2361,7 @@ test_append_uri_pathel(void)
mu_assert ("test_append_uri_pathel: wrong result",
strcmp (dest.base, test_array[i].expected_result) == 0);
xfree (dest.base);
}
return NULL;

View File

@@ -1,7 +1,7 @@
/* Declarations for url.c.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -36,6 +36,7 @@ as that of the covered work. */
#define DEFAULT_HTTP_PORT 80
#define DEFAULT_FTP_PORT 21
#define DEFAULT_HTTPS_PORT 443
#define DEFAULT_FTPS_IMPLICIT_PORT 990
/* This represents how many characters less than the OS max name length a file
* should be. More precisely, a file name should be at most
@@ -70,6 +71,9 @@ enum url_scheme {
SCHEME_HTTPS,
#endif
SCHEME_FTP,
#ifdef HAVE_SSL
SCHEME_FTPS,
#endif
SCHEME_INVALID
};
@@ -106,6 +110,7 @@ struct url
char *url_escape (const char *);
char *url_escape_unsafe_and_reserved (const char *);
void url_unescape (char *);
void url_unescape_except_reserved (char *);
struct url *url_parse (const char *, int *, struct iri *iri, bool percent_encode);
char *url_error (const char *, int);

View File

@@ -1,7 +1,7 @@
/* Various utility functions.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -336,7 +336,7 @@ aprintf (const char *fmt, ...)
{ /* maybe we have some wrong
format string? */
logprintf (LOG_ALWAYS,
_("%s: aprintf: text buffer is too big (%ld bytes), "
_("%s: aprintf: text buffer is too big (%d bytes), "
"aborting.\n"),
exec_name, size); /* printout a log message */
abort (); /* and abort... */
@@ -1284,7 +1284,10 @@ free_vec (char **vec)
{
char **p = vec;
while (*p)
xfree (*p++);
{
xfree (*p);
p++;
}
xfree (vec);
}
}
@@ -2503,6 +2506,21 @@ get_max_length (const char *path, int length, int name)
return ret;
}
void
wg_hex_to_string (char *str_buffer, const char *hex_buffer, size_t hex_len)
{
size_t i;
for (i = 0; i < hex_len; i++)
{
/* Each byte takes 2 characters. */
sprintf (str_buffer + 2 * i, "%02x", hex_buffer[i] & 0xFF);
}
/* Null-terminate result. */
str_buffer[2 * i] = '\0';
}
#ifdef TESTING
const char *

View File

@@ -1,7 +1,7 @@
/* Declarations for utils.c.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -32,6 +32,8 @@ as that of the covered work. */
#ifndef UTILS_H
#define UTILS_H
# include <stdlib.h>
/* Constant is using when we don`t know attempted size exactly */
#define UNKNOWN_ATTEMPTED_SIZE -3
@@ -155,6 +157,8 @@ long get_max_length (const char *path, int length, int name);
size_t strlcpy (char *dst, const char *src, size_t size);
#endif
void wg_hex_to_string (char *str_buffer, const char *hex_buffer, size_t hex_len);
extern unsigned char char_prop[];
#endif /* UTILS_H */

View File

@@ -1,5 +1,5 @@
/* Extern declarations for printing version information
Copyright (C) 2013 Free Software Foundation, Inc.
Copyright (C) 2013, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.

View File

@@ -1,5 +1,5 @@
/* Utility functions for writing WARC files.
Copyright (C) 2011, 2012 Free Software Foundation, Inc.
Copyright (C) 2011, 2012, 2015 Free Software Foundation, Inc.
This file is part of GNU Wget.
@@ -27,10 +27,6 @@ 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. */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "wget.h"
#include "hash.h"
#include "utils.h"
@@ -102,7 +98,7 @@ static bool warc_write_ok;
static FILE *warc_current_cdx_file;
/* The record id of the warcinfo record of the current WARC file. */
static char *warc_current_warcinfo_uuid_str;
static char warc_current_warcinfo_uuid_str[48];
/* The file name of the current WARC file. */
static char *warc_current_filename;
@@ -404,7 +400,7 @@ warc_write_date_header (const char *timestamp)
the current WARC record. If IP is NULL, no header will
be written. */
static bool
warc_write_ip_header (ip_address *ip)
warc_write_ip_header (const ip_address *ip)
{
if (ip != NULL)
return warc_write_header ("WARC-IP-Address", print_address (ip));
@@ -435,9 +431,7 @@ warc_sha1_stream_with_payload (FILE *stream, void *res_block, void *res_payload,
off_t pos;
off_t sum;
char *buffer = malloc (BLOCKSIZE + 72);
if (!buffer)
return 1;
char *buffer = xmalloc (BLOCKSIZE + 72);
/* Initialize the computation context. */
sha1_init_ctx (&ctx_block);
@@ -542,14 +536,17 @@ warc_sha1_stream_with_payload (FILE *stream, void *res_block, void *res_payload,
/* Converts the SHA1 digest to a base32-encoded string.
"sha1:DIGEST\0" (Allocates a new string for the response.) */
static char *
warc_base32_sha1_digest (char *sha1_digest)
warc_base32_sha1_digest (const char *sha1_digest, char *sha1_base32, size_t sha1_base32_size)
{
/* length: "sha1:" + digest + "\0" */
char *sha1_base32 = malloc (BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5 );
base32_encode (sha1_digest, SHA1_DIGEST_SIZE, sha1_base32 + 5,
BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1);
memcpy (sha1_base32, "sha1:", 5);
sha1_base32[BASE32_LENGTH(SHA1_DIGEST_SIZE) + 5] = '\0';
if (sha1_base32_size >= BASE32_LENGTH(SHA1_DIGEST_SIZE) + 5 + 1)
{
memcpy (sha1_base32, "sha1:", 5);
base32_encode (sha1_digest, SHA1_DIGEST_SIZE, sha1_base32 + 5,
sha1_base32_size - 5);
}
else
*sha1_base32 = 0;
return sha1_base32;
}
@@ -571,18 +568,14 @@ warc_write_digest_headers (FILE *file, long payload_offset)
if (warc_sha1_stream_with_payload (file, sha1_res_block,
sha1_res_payload, payload_offset) == 0)
{
char *digest;
char digest[BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5];
digest = warc_base32_sha1_digest (sha1_res_block);
warc_write_header ("WARC-Block-Digest", digest);
xfree (digest);
warc_write_header ("WARC-Block-Digest",
warc_base32_sha1_digest (sha1_res_block, digest, sizeof(digest)));
if (payload_offset >= 0)
{
digest = warc_base32_sha1_digest (sha1_res_payload);
warc_write_header ("WARC-Payload-Digest", digest);
xfree (digest);
}
warc_write_header ("WARC-Payload-Digest",
warc_base32_sha1_digest (sha1_res_payload, digest, sizeof(digest)));
}
}
}
@@ -734,7 +727,7 @@ warc_uuid_str (char *urn_str)
/* Write a warcinfo record to the current file.
Updates warc_current_warcinfo_uuid_str. */
static bool
warc_write_warcinfo_record (char *filename)
warc_write_warcinfo_record (const char *filename)
{
FILE *warc_tmp;
char timestamp[22];
@@ -743,7 +736,6 @@ warc_write_warcinfo_record (char *filename)
/* Write warc-info record as the first record of the file. */
/* We add the record id of this info record to the other records in the
file. */
warc_current_warcinfo_uuid_str = (char *) malloc (48);
warc_uuid_str (warc_current_warcinfo_uuid_str);
warc_timestamp (timestamp, sizeof(timestamp));
@@ -827,14 +819,15 @@ warc_start_new_file (bool meta)
if (warc_current_file != NULL)
fclose (warc_current_file);
xfree (warc_current_warcinfo_uuid_str);
*warc_current_warcinfo_uuid_str = 0;
xfree (warc_current_filename);
warc_current_file_number++;
base_filename_length = strlen (opt.warc_filename);
/* filename format: base + "-" + 5 digit serial number + ".warc.gz" */
new_filename = malloc (base_filename_length + 1 + 5 + 8 + 1);
new_filename = xmalloc (base_filename_length + 1 + 5 + 8 + 1);
warc_current_filename = new_filename;
/* If max size is enabled, we add a serial number to the file names. */
@@ -995,7 +988,7 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
{
/* This is a valid line with a valid checksum. */
struct warc_cdx_record *rec;
rec = malloc (sizeof (struct warc_cdx_record));
rec = xmalloc (sizeof (struct warc_cdx_record));
rec->url = original_url;
rec->uuid = record_id;
memcpy (rec->digest, checksum_v, SHA1_DIGEST_SIZE);
@@ -1098,7 +1091,7 @@ _("CDX file does not list record ids. (Missing column 'u'.)\n"));
digest. Returns NULL if the url is not found or if the payload digest
does not match, or if CDX deduplication is disabled. */
static struct warc_cdx_record *
warc_find_duplicate_cdx_record (char *url, char *sha1_digest_payload)
warc_find_duplicate_cdx_record (const char *url, char *sha1_digest_payload)
{
struct warc_cdx_record *rec_existing;
@@ -1228,7 +1221,7 @@ warc_close (void)
if (warc_current_file != NULL)
{
warc_write_metadata ();
xfree (warc_current_warcinfo_uuid_str);
*warc_current_warcinfo_uuid_str = 0;
fclose (warc_current_file);
}
if (warc_current_cdx_file != NULL)
@@ -1293,8 +1286,9 @@ warc_tempfile (void)
Calling this function will close body.
Returns true on success, false on error. */
bool
warc_write_request_record (char *url, char *timestamp_str, char *record_uuid,
ip_address *ip, FILE *body, off_t payload_offset)
warc_write_request_record (const char *url, const char *timestamp_str,
const char *record_uuid, const ip_address *ip,
FILE *body, off_t payload_offset)
{
warc_write_start_record ();
warc_write_header ("WARC-Type", "request");
@@ -1382,18 +1376,18 @@ warc_write_cdx_record (const char *url, const char *timestamp_str,
Calling this function will close body.
Returns true on success, false on error. */
static bool
warc_write_revisit_record (char *url, char *timestamp_str,
char *concurrent_to_uuid, char *payload_digest,
char *refers_to, ip_address *ip, FILE *body)
warc_write_revisit_record (const char *url, const char *timestamp_str,
const char *concurrent_to_uuid, const char *payload_digest,
const char *refers_to, const ip_address *ip, FILE *body)
{
char revisit_uuid [48];
char *block_digest = NULL;
char block_digest[BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5];
char sha1_res_block[SHA1_DIGEST_SIZE];
warc_uuid_str (revisit_uuid);
sha1_stream (body, sha1_res_block);
block_digest = warc_base32_sha1_digest (sha1_res_block);
warc_base32_sha1_digest (sha1_res_block, block_digest, sizeof(block_digest));
warc_write_start_record ();
warc_write_header ("WARC-Type", "revisit");
@@ -1413,7 +1407,6 @@ warc_write_revisit_record (char *url, char *timestamp_str,
warc_write_end_record ();
fclose (body);
xfree (block_digest);
return warc_write_ok;
}
@@ -1432,13 +1425,13 @@ warc_write_revisit_record (char *url, char *timestamp_str,
Calling this function will close body.
Returns true on success, false on error. */
bool
warc_write_response_record (char *url, char *timestamp_str,
char *concurrent_to_uuid, ip_address *ip,
FILE *body, off_t payload_offset, char *mime_type,
int response_code, char *redirect_location)
warc_write_response_record (const char *url, const char *timestamp_str,
const char *concurrent_to_uuid, const ip_address *ip,
FILE *body, off_t payload_offset, const char *mime_type,
int response_code, const char *redirect_location)
{
char *block_digest = NULL;
char *payload_digest = NULL;
char block_digest[BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5];
char payload_digest[BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5];
char sha1_res_block[SHA1_DIGEST_SIZE];
char sha1_res_payload[SHA1_DIGEST_SIZE];
char response_uuid [48];
@@ -1471,17 +1464,16 @@ warc_write_response_record (char *url, char *timestamp_str,
}
/* Send the original payload digest. */
payload_digest = warc_base32_sha1_digest (sha1_res_payload);
warc_base32_sha1_digest (sha1_res_payload, payload_digest, sizeof(payload_digest));
result = warc_write_revisit_record (url, timestamp_str,
concurrent_to_uuid, payload_digest, rec_existing->uuid,
ip, body);
xfree (payload_digest);
return result;
}
block_digest = warc_base32_sha1_digest (sha1_res_block);
payload_digest = warc_base32_sha1_digest (sha1_res_payload);
warc_base32_sha1_digest (sha1_res_block, block_digest, sizeof(block_digest));
warc_base32_sha1_digest (sha1_res_payload, payload_digest, sizeof(payload_digest));
}
}
@@ -1516,9 +1508,6 @@ warc_write_response_record (char *url, char *timestamp_str,
response_uuid);
}
xfree (block_digest);
xfree (payload_digest);
return warc_write_ok;
}
@@ -1535,16 +1524,18 @@ warc_write_response_record (char *url, char *timestamp_str,
Calling this function will close body.
Returns true on success, false on error. */
static bool
warc_write_record (const char *record_type, char *resource_uuid,
warc_write_record (const char *record_type, const char *resource_uuid,
const char *url, const char *timestamp_str,
const char *concurrent_to_uuid,
ip_address *ip, const char *content_type, FILE *body,
const ip_address *ip, const char *content_type, FILE *body,
off_t payload_offset)
{
if (resource_uuid == NULL)
{
resource_uuid = alloca (48);
warc_uuid_str (resource_uuid);
/* using uuid_buf allows const for resource_uuid in function declaration */
char *uuid_buf = alloca (48);
warc_uuid_str (uuid_buf);
resource_uuid = uuid_buf;
}
if (content_type == NULL)
@@ -1580,9 +1571,9 @@ warc_write_record (const char *record_type, char *resource_uuid,
Calling this function will close body.
Returns true on success, false on error. */
bool
warc_write_resource_record (char *resource_uuid, const char *url,
warc_write_resource_record (const char *resource_uuid, const char *url,
const char *timestamp_str, const char *concurrent_to_uuid,
ip_address *ip, const char *content_type, FILE *body,
const ip_address *ip, const char *content_type, FILE *body,
off_t payload_offset)
{
return warc_write_record ("resource",
@@ -1602,7 +1593,7 @@ warc_write_resource_record (char *resource_uuid, const char *url,
Calling this function will close body.
Returns true on success, false on error. */
bool
warc_write_metadata_record (char *record_uuid, const char *url,
warc_write_metadata_record (const char *record_uuid, const char *url,
const char *timestamp_str, const char *concurrent_to_uuid,
ip_address *ip, const char *content_type, FILE *body,
off_t payload_offset)

View File

@@ -12,15 +12,15 @@ char * warc_timestamp (char *timestamp, size_t timestamp_size);
FILE * warc_tempfile (void);
bool warc_write_request_record (char *url, char *timestamp_str,
char *concurrent_to_uuid, ip_address *ip, FILE *body, off_t payload_offset);
bool warc_write_response_record (char *url, char *timestamp_str,
char *concurrent_to_uuid, ip_address *ip, FILE *body, off_t payload_offset,
char *mime_type, int response_code, char *redirect_location);
bool warc_write_resource_record (char *resource_uuid, const char *url,
const char *timestamp_str, const char *concurrent_to_uuid, ip_address *ip,
bool warc_write_request_record (const char *url, const char *timestamp_str,
const char *concurrent_to_uuid, const ip_address *ip, FILE *body, off_t payload_offset);
bool warc_write_response_record (const char *url, const char *timestamp_str,
const char *concurrent_to_uuid, const ip_address *ip, FILE *body, off_t payload_offset,
const char *mime_type, int response_code, const char *redirect_location);
bool warc_write_resource_record (const char *resource_uuid, const char *url,
const char *timestamp_str, const char *concurrent_to_uuid, const ip_address *ip,
const char *content_type, FILE *body, off_t payload_offset);
bool warc_write_metadata_record (char *record_uuid, const char *url,
bool warc_write_metadata_record (const char *record_uuid, const char *url,
const char *timestamp_str, const char *concurrent_to_uuid, ip_address *ip,
const char *content_type, FILE *body, off_t payload_offset);

View File

@@ -1,7 +1,7 @@
/* Miscellaneous declarations.
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
Inc.
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2015 Free Software
Foundation, Inc.
This file is part of GNU Wget.
@@ -48,12 +48,15 @@ as that of the covered work. */
/* Disable assertions when debug support is not compiled in. */
#ifndef ENABLE_DEBUG
#ifndef NDEBUG
# define NDEBUG
#endif
#endif
/* Is OpenSSL or GNUTLS available? */
#if defined HAVE_LIBSSL || defined HAVE_LIBSSL32 || defined HAVE_LIBGNUTLS
# define HAVE_SSL
# define HAVE_HSTS /* There's no sense in enabling HSTS without SSL */
#endif
/* `gettext (FOO)' is long to write, so we use `_(FOO)'. If NLS is
@@ -331,7 +334,9 @@ enum
SEND_NOCACHE = 0x0008, /* send Pragma: no-cache directive */
ACCEPTRANGES = 0x0010, /* Accept-ranges header was found */
ADDED_HTML_EXTENSION = 0x0020, /* added ".html" extension due to -E */
TEXTCSS = 0x0040 /* document is of type text/css */
TEXTCSS = 0x0040, /* document is of type text/css */
IF_MODIFIED_SINCE = 0x0080, /* use if-modified-since header */
METALINK_METADATA = 0x0100 /* use HTTP response for Metalink metadata */
};
/* Universal error type -- used almost everywhere. Error reporting of
@@ -346,12 +351,17 @@ typedef enum
FTPSRVERR, FTPRETRINT, FTPRESTFAIL, URLERROR, FOPENERR,
FOPEN_EXCL_ERR, FWRITEERR, HEOF, GATEWAYTIMEOUT,
HERR, RETROK, RECLEVELEXC, WRONGCODE,
FTPINVPASV, FTPNOPASV, CONTNOTSUPPORTED, RETRUNNEEDED, RETRFINISHED,
FTPINVPASV, FTPNOPASV, FTPNOPBSZ, FTPNOPROT, FTPNOAUTH,
CONTNOTSUPPORTED, RETRUNNEEDED, RETRFINISHED,
READERR, TRYLIMEXC, FILEBADFILE, RANGEERR,
RETRBADPATTERN, PROXERR,
AUTHFAILED, QUOTEXC, WRITEFAILED, SSLINITFAILED, VERIFCERTERR,
UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED, ATTRMISSING, UNKNOWNATTR,
WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR
WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR,
TIMECONV_ERR,
METALINK_PARSE_ERROR, METALINK_RETR_ERROR,
METALINK_CHKSUM_ERROR, METALINK_SIG_ERROR, METALINK_MISSING_RESOURCE,
RETR_WITH_METALINK
} uerr_t;
/* 2005-02-19 SMS.

View File

@@ -1,5 +1,5 @@
# Makefile for `wget' utility
# Copyright (C) 2013 Free Software Foundation, Inc.
# Copyright (C) 2013, 2015 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
@@ -26,39 +26,55 @@
# as that of the covered work.
if METALINK_IS_ENABLED
METALINK_TESTS = Test-metalink-xml.py \
Test-metalink-http.py
else
METALINK_TESTS =
endif
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 =
if WITH_SSL
AM_TESTS_ENVIRONMENT += export SSL_TESTS=1;
endif
EXTRA_DIST = certs conf exc misc server test README $(TESTS) $(XFAIL_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--convert-links--content-on-error.py \
Test-cookie-401.py \
Test-cookie-domain-mismatch.py \
Test-cookie-expires.py \
Test-cookie.py \
Test-Head.py \
Test--https.py \
Test--https-crl.py \
Test-hsts.py \
Test-O.py \
Test-Post.py \
Test-504.py \
Test--spider-r.py \
Test--rejected-log.py \
Test-redirect-crash.py \
Test-reserved-chars.py \
Test-condget.py \
$(METALINK_TESTS)
endif
EXTRA_DIST = certs conf exc misc server test README $(TESTS)
TEST_EXTENSIONS = .py
PY_LOG_COMPILER = python3

View File

@@ -124,7 +124,7 @@ 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 timestamp string should be in a format: "YYYY-MM-DD HH:MM:SS" in UTC zone.
The rules object is a dictionary element, with the key as the Rule Name and
value as the Rule Data. In most cases, the Rule Data is another dictionary.
@@ -184,7 +184,8 @@ This section lists the currently supported File Rules and their structure.
* 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.
ExpectHeader. Additionally you can specify a list of strings as <Header Data>
if you want the header repeated with multiple values.
* Response : The HTTP Response Code to send to a request for this File.
The value is an Integer that represents a valid HTTP Response Code.

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
"""
This test ensures that Wget link conversion works also on HTTP error pages.
"""
TEST_NAME = "Test--convert-links--content-on-error"
############# File Definitions ###############################################
a_x_FileContent = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="/b/y.html"></a>
</body>
</html>
"""
a_x_LocalFileContent = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="../b/y.html"></a>
</body>
</html>
"""
error_FileContent = '404 page content'
error_FileRules = {
'Response': 404 ,
'SendHeader': {
'Content-Length': len(error_FileContent),
'Content-Type': 'text/plain',
}
}
a_x_File = WgetFile ("a/x.html", a_x_FileContent)
robots_File = WgetFile ("robots.txt", '')
error_File = WgetFile ("b/y.html", error_FileContent, rules=error_FileRules)
B_File = WgetFile ("a/x.html", a_x_LocalFileContent)
WGET_OPTIONS = "--no-host-directories -r -l2 --convert-links --content-on-error"
WGET_URLS = [["a/x.html"]]
Files = [[a_x_File, robots_File, error_File]]
ExpectedReturnCode = 8
ExpectedDownloadedFiles = [B_File, robots_File, error_File]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
).begin ()
exit (err)

View File

@@ -9,6 +9,9 @@ import os
This test ensures that Wget can download files from HTTPS Servers
"""
TEST_NAME = "HTTPS CRL"
if os.getenv('SSL_TESTS') is None:
exit (77)
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File2 = "With lemon or cream?"

View File

@@ -9,6 +9,9 @@ import os
This test ensures that Wget can download files from HTTPS Servers
"""
TEST_NAME = "HTTPS Downloads"
if os.getenv('SSL_TESTS') is None:
exit (77)
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File2 = "With lemon or cream?"

102
testenv/Test--rejected-log.py Executable file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
"""
This test executed Wget in recursive mode with a rejected log outputted.
"""
TEST_NAME = "Rejected Log"
############# File Definitions ###############################################
mainpage = """
<html>
<head>
<title>Main Page</title>
</head>
<body>
<p>
Recurse to a <a href="http://127.0.0.1:{{port}}/secondpage.html">second page</a>.
</p>
</body>
</html>
"""
secondpage = """
<html>
<head>
<title>Second Page</title>
</head>
<body>
<p>
Recurse to a <a href="http://127.0.0.1:{{port}}/thirdpage.html">third page</a>.
Try the blacklisted <a href="http://127.0.0.1:{{port}}/index.html">main page</a>.
</p>
</body>
</html>
"""
thirdpage = """
<html>
<head>
<title>Third Page</title>
</head>
<body>
<p>
Try a hidden <a href="http://127.0.0.1:{{port}}/dummy.txt">dummy file</a>.
Try to leave to <a href="http://no.such.domain/">another domain</a>.
</p>
</body>
</html>
"""
robots = """
User-agent: *
Disallow: /dummy.txt
"""
log = """\
REASON U_URL U_SCHEME U_HOST U_PORT U_PATH U_PARAMS U_QUERY U_FRAGMENT P_URL P_SCHEME P_HOST P_PORT P_PATH P_PARAMS P_QUERY P_FRAGMENT
BLACKLIST http%3A//127.0.0.1%3A{{port}}/index.html SCHEME_HTTP 127.0.0.1 {{port}} index.html http%3A//127.0.0.1%3A{{port}}/secondpage.html SCHEME_HTTP 127.0.0.1 {{port}} secondpage.html
ROBOTS http%3A//127.0.0.1%3A{{port}}/dummy.txt SCHEME_HTTP 127.0.0.1 {{port}} dummy.txt http%3A//127.0.0.1%3A{{port}}/thirdpage.html SCHEME_HTTP 127.0.0.1 {{port}} thirdpage.html
SPANNEDHOST http%3A//no.such.domain/ SCHEME_HTTP no.such.domain 80 http%3A//127.0.0.1%3A{{port}}/thirdpage.html SCHEME_HTTP 127.0.0.1 {{port}} thirdpage.html
"""
dummyfile = "Don't care."
index_html = WgetFile ("index.html", mainpage)
secondpage_html = WgetFile ("secondpage.html", secondpage)
thirdpage_html = WgetFile ("thirdpage.html", thirdpage)
robots_txt = WgetFile ("robots.txt", robots)
dummy_txt = WgetFile ("dummy.txt", dummyfile)
log_csv = WgetFile ("log.csv", log)
WGET_OPTIONS = "-nd -r --rejected-log log.csv"
WGET_URLS = [["index.html"]]
Files = [[index_html, secondpage_html, thirdpage_html, robots_txt, dummy_txt]]
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [index_html, secondpage_html, thirdpage_html, robots_txt, log_csv]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
).begin ()
exit (err)

View File

@@ -18,7 +18,10 @@ File1_rules = {
"Authentication" : {
"Type" : "Both",
"User" : "Sauron",
"Pass" : "TheEye"
"Pass" : "TheEye",
"Parm" : {
"qop" : "auth"
}
},
"RejectHeader" : {
"Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
@@ -28,7 +31,10 @@ File2_rules = {
"Authentication" : {
"Type" : "Both_inline",
"User" : "Sauron",
"Pass" : "TheEye"
"Pass" : "TheEye",
"Parm" : {
"qop" : "auth"
}
},
"RejectHeader" : {
"Authorization" : "Basic U2F1cm9uOlRoZUV5ZQ=="
@@ -38,7 +44,11 @@ File3_rules = {
"Authentication" : {
"Type" : "Digest",
"User" : "Sauron",
"Pass" : "TheEye"
"Pass" : "TheEye",
"Parm" : {
"qop" : "auth"
}
}
}

View File

@@ -9,23 +9,39 @@ from misc.wget_file import WgetFile
TEST_NAME = "Digest Authorization"
############# File Definitions ###############################################
File1 = "Need a cookie?"
File2 = "Want cookies with milk!"
File1_rules = {
"Authentication" : {
"Type" : "Digest",
"User" : "Pacman",
"Pass" : "Omnomnom"
"Pass" : "Omnomnom",
"Parm" : {
"qop" : "auth"
}
}
}
File2_rules = {
"Authentication" : {
"Type" : "Digest",
"User" : "Pacman",
"Pass" : "Omnomnom",
"Parm" : {
"qop" : None
}
}
}
A_File = WgetFile ("File1", File1, rules=File1_rules)
B_File = WgetFile ("File2", File2, rules=File2_rules)
WGET_OPTIONS = "--user=Pacman --password=Omnomnom"
WGET_URLS = [["File1"]]
WGET_URLS = [["File1", "File2"]]
Files = [[A_File]]
Files = [[A_File, B_File]]
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [A_File]
ExpectedDownloadedFiles = [A_File, B_File]
################ Pre and Post Test Hooks #####################################
pre_test = {

140
testenv/Test-condget.py Executable file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
"""
Simple test for HTTP Conditional-GET Requests using the -N command
"""
TEST_NAME = "HTTP Conditional-GET Requests"
############# File Definitions ###############################################
# Keep same length !
Cont1 = """THIS IS 1 FILE"""
Cont2 = """THIS IS 2 FILE"""
Cont3 = """THIS IS 3 FILE"""
Cont4 = """THIS IS 4 FILE"""
# Local Wget files
# These have same timestamp as remote files
UpToDate_Local_File1 = WgetFile ("UpToDateFile1", Cont1, timestamp="1995-01-01 00:00:00")
UpToDate_Local_File2 = WgetFile ("UpToDateFile2", Cont1, timestamp="1995-01-01 00:00:00")
UpToDate_Local_File3 = WgetFile ("UpToDateFile3", Cont1, timestamp="1995-01-01 00:00:00")
# This is newer than remote (expected same behaviour as for above files)
Newer_Local_File = WgetFile ("NewerFile", Cont1, timestamp="1995-02-02 02:02:02")
# This is older than remote - should be clobbered
Outdated_Local_File = WgetFile ("UpdatedFile", Cont2, timestamp="1990-01-01 00:00:00")
UpToDate_Rules1 = {
"SendHeader" : {
# RFC1123 format
"Last-Modified" : "Sun, 01 Jan 1995 00:00:00 GMT",
},
"Response": 304,
"ExpectHeader" : {
"If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
},
}
UpToDate_Rules2 = {
"SendHeader" : {
# RFC850 format
"Last-Modified" : "Sunday, 01-Jan-95 00:00:00 GMT",
},
"Response": 304,
"ExpectHeader" : {
"If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
},
}
UpToDate_Rules3 = {
"SendHeader" : {
# Asctime format
"Last-Modified" : "Sun Jan 01 00:00:00 1995",
},
"Response": 304,
"ExpectHeader" : {
"If-Modified-Since" : "Sun, 01 Jan 1995 00:00:00 GMT"
},
}
Newer_Rules = {
"SendHeader" : {
# Asctime format
"Last-Modified" : "Sun Jan 01 00:00:00 1995",
},
"Response": 304,
"ExpectHeader" : {
"If-Modified-Since" : "Thu, 02 Feb 1995 02:02:02 GMT"
},
}
Outdated_Rules = {
"SendHeader" : {
# RFC850 format
"Last-Modified" : "Thursday, 01-Jan-15 00:00:00 GMT",
},
"ExpectHeader" : {
"If-Modified-Since" : "Mon, 01 Jan 1990 00:00:00 GMT",
},
}
UpToDate_Server_File1 = WgetFile ("UpToDateFile1", Cont3, rules=UpToDate_Rules1)
UpToDate_Server_File2 = WgetFile ("UpToDateFile2", Cont3, rules=UpToDate_Rules2)
UpToDate_Server_File3 = WgetFile ("UpToDateFile3", Cont3, rules=UpToDate_Rules3)
Newer_Server_File = WgetFile ("NewerFile", Cont3, rules=Newer_Rules)
Updated_Server_File = WgetFile ("UpdatedFile", Cont4, rules=Outdated_Rules)
WGET_OPTIONS = "-N"
WGET_URLS = [["UpToDateFile1", "UpToDateFile2", "UpToDateFile3", "NewerFile",
"UpdatedFile", ]]
Files = [[UpToDate_Server_File1, UpToDate_Server_File2, UpToDate_Server_File3,
Newer_Server_File, Updated_Server_File, ]]
Existing_Files = [UpToDate_Local_File1, UpToDate_Local_File2,
UpToDate_Local_File3, Newer_Local_File, Outdated_Local_File]
ExpectedReturnCode = 0
# The uptodate file should not be downloaded
ExpectedDownloadedFiles = [UpToDate_Local_File1, UpToDate_Local_File2,
UpToDate_Local_File3, Newer_Local_File,
Updated_Server_File]
# Kind of hack to ensure proper request types
Request_List = [
[
"GET /UpToDateFile1",
"GET /UpToDateFile2",
"GET /UpToDateFile3",
"GET /NewerFile",
"GET /UpdatedFile",
]
]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : Request_List,
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
).begin ()
exit (err)

82
testenv/Test-hsts.py Executable file
View File

@@ -0,0 +1,82 @@
#!/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 time
import os
"""
This test makes sure Wget can parse a given HSTS database and apply the indicated HSTS policy.
"""
TEST_NAME = "HSTS basic test"
print (os.getenv('SSL_TESTS'))
if os.getenv('SSL_TESTS') is None:
exit (77)
def hsts_database_path():
hsts_file = ".wget-hsts-testenv"
return os.path.abspath(hsts_file)
def create_hsts_database(path, host, port):
# we want the current time as an integer,
# not as a floating point
curtime = int(time.time())
max_age = "123456"
f = open(path, "w")
f.write("# dummy comment\n")
f.write(host + "\t" + str(port) + "\t0\t" + str(curtime) + "\t" + max_age + "\n")
f.close()
File_Name = "hw"
File_Content = "Hello, world!"
File = WgetFile(File_Name, File_Content)
Hsts_File_Path = hsts_database_path()
CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
WGET_OPTIONS = "--hsts-file=" + Hsts_File_Path + " --ca-certificate=" + CAFILE
WGET_URLS = [[File_Name]]
Files = [[File]]
Servers = [HTTPS]
Requests = ["http"]
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [File]
pre_test = {
"ServerFiles" : Files,
"Domains" : ["localhost"]
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetCode" : ExpectedReturnCode,
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
test = HTTPTest(
name = TEST_NAME,
pre_hook = pre_test,
post_hook = post_test,
test_params = test_options,
protocols = Servers,
req_protocols = Requests
)
# start the web server and create the temporary HSTS database
test.setup()
create_hsts_database(Hsts_File_Path, 'localhost', test.port)
err = test.begin()
# remove the temporary HSTS database
os.unlink(hsts_database_path())
exit(err)

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