225 Commits

Author SHA1 Message Date
Giuseppe Scrivano
bd7f36705b NEWS: update 2016-06-09 17:31:57 +02:00
Giuseppe Scrivano
e996e322ff ftp: understand --trust-server-names on a HTTP->FTP redirect
If not --trust-server-names is used, FTP will also get the destination
file name from the original url specified by the user instead of the
redirected url.  Closes CVE-2016-4971.

* src/ftp.c (ftp_get_listing): Add argument original_url.
(getftp): Likewise.
(ftp_loop_internal): Likewise.  Use original_url to generate the
file name if --trust-server-names is not provided.
(ftp_retrieve_glob): Likewise.
(ftp_loop): Likewise.

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2016-06-09 15:02:49 +02:00
Tim Rühsen
2bdfc4f521 Fix warnings for --disable-iri configure flag
* src/iri.h: Fix #define for parse_charset
* src/html-url.c: Surround some IRI code parts by #ifdef ENABLE_IRI
* src/http.c: Likewise
* src/iri.h: Likewise
* src/recur.c: Likewise
* src/retr.c: Likewise
2016-06-07 12:52:59 +02:00
Tim Rühsen
2c736abb4c Fix warning about redefinition of MAP_FAILED
* src/sysdep.h: Removed definition of MAP_FAILED
* src/utils.c: Check and define MAP_FAILED after including sys/mmap.h
2016-06-07 09:56:01 +02:00
Tim Rühsen
7c0752c4cb Add new Test for missing scheme behavior
* testenv/Makefile.am: Add Test-missing-scheme-retval.py
* testenv: New file Test-missing-scheme-retval.py

Idea and Perl implementation by Zdenek Dohnal <zdohnal@redhat.com>
2016-06-03 10:16:40 +02:00
Tim Rühsen
302aa79abb Fallback to pod2man without utf-8 on error
* doc/Makefile.am: Fallback to pod2man without utf-8 on error
2016-05-27 16:44:50 +02:00
Ander Juaristi
5224d752a5 Correct HSTS debug message
* src/main.c (save_hsts): save the in-memory HSTS database to a file
   only if something changed.
 * src/hsts.c (struct hsts_store): new field 'changed'.
   (hsts_match): update field 'changed' accordingly.
   (hsts_store_entry): update field 'changed' accordingly.
   (hsts_store_has_changed): new function.
 * src/hsts.h (hsts_store_has_changed): new function.
2016-05-26 16:37:51 +02:00
Ander Juaristi
2aaf12990c Check the HSTS file is not world-writable
* hsts.c (hsts_file_access_valid): check that the file is a regular
   file, and that it's not world-writable.
   (hsts_store_open): if the HSTS database file does not meet the
   above requirements, disable HSTS at all.
2016-05-26 16:29:29 +02:00
Tim Rühsen
2e6f629061 Improve description of Perl libraries needed for test suite
* README.checkout: Improve text about Perl libraries
2016-05-24 09:38:15 +02:00
Tim Rühsen
a952f81f3e Remove special handling for Emacs in progress bar code
* src/progress.c: Remove special 'emacs' code

Fixes #47989
2016-05-23 21:46:29 +02:00
Jernej Simončič
42cc84b6b6 Fix xsleep() for Windows (trivial change)
* src/mswindows.c (xsleep): Fix check for number of seconds
2016-04-25 15:50:23 +02:00
Sergio Gelato
96ab9cad88 More accurate log message from do_conversion()
* src/iri.c (do_conversion): More accurate log message
2016-04-17 15:28:48 +02:00
Tim Rühsen
268163444d Include sys/select.h if HAVE_LIBCARES
* src/hosts.c: Include sys/select.h if HAVE_LIBCARES

Reported-by: Gisle Vanem <gvanem@yahoo.no>
2016-04-17 14:18:55 +02:00
Gisle Vanem
53800415a9 Fix Windows gnulib/c-ares incompatibility of select()
* src/host.c: Undef 'select' on Windows
2016-04-17 14:15:51 +02:00
Tim Rühsen
528770ca8b Set X flags for python tests
* testenv/*.py: Set eXecute flags

Regression from commit 926e42d467
2016-04-15 21:36:51 +02:00
Ander Juaristi
2f1c6a05c8 Strictly comply with RFC 6797
* src/hsts.c (hsts_store_entry): strictly comply with RFC 6797.

RFC 6797 states in section 8.1 that the UA's cached information should
only be updated if:

    "either or both of the max-age and includeSubDomains header field
    value tokens are conveying information different than that already
    maintained by the UA."
2016-04-11 16:44:47 +02:00
Ander Juaristi
33d860e1ef Correct HSTS database file description
* src/hsts.c (hsts_store_dump): s/[:port]/<port>/
2016-04-11 16:44:41 +02:00
moparisthebest
99fc712f21 Implement tests for new pinnedpubkey option
* testenv/Makefile.am: Add new tests
* testenv/Test-pinnedpubkey-der-https.py: New test
* testenv/Test-pinnedpubkey-der-no-check-https.py: New Test
* testenv/Test-pinnedpubkey-hash-https.py: New test
* testenv/Test-pinnedpubkey-hash-no-check-fail-https.py: New test
* testenv/Test-pinnedpubkey-pem-fail-https.py: New test
* testenv/Test-pinnedpubkey-pem-https.py: New test
* testenv/certs/README: How to generate public keys with openssl tool
* testenv/certs/server-pubkey.der: New key file (DER format)
* testenv/certs/server-pubkey.pem: New key file (PEM format)
2016-04-11 16:25:09 +02:00
moparisthebest
54746578e9 Implement --pinnedpubkey option to pin public keys
* doc/wget.texi: Add description for --pinnedpubkey
* src/gnutls.c: New function pkp_pin_peer_pubkey(),
  (ssl_check_certificate): Check pinned cert via pkp_pin_peer_pubkey()
* src/init.c: Add option --pinnedpubkey
* src/main.c: Add option --pinnedpubkey
* src/openssl.c: New function pkp_pin_peer_pubkey(),
  (ssl_check_certificate): Check pinned cert via pkp_pin_peer_pubkey()
* src/options.h: Add new option variable 'pinnedpubkey'
* src/utils.c: New functions wg_pubkey_pem_to_der(), wg_pin_peer_pubkey()
* src/utils.h: Add prototype for wg_pin_peer_pubkey()
2016-04-11 16:18:05 +02:00
Tim Rühsen
926e42d467 Use test file name for temp working directory name
* testenv/test/base_test.py (__init__): Use test file name for name,
  remove 'name' parameter
* testenv/test/http_test.py (__init__): Remove 'name' parameter
* testenv/*.py: Remove TEST_NAME

Using a fixed string (TEST_NAME) to build the working directory
for testing caused random failures (or successes) when tests
share the same TEST_NAME value. Not easy to find without digging
into the python test suite code.
We now use the test file name, which is unique within the test
environment.
2016-04-11 15:35:05 +02:00
Tim Rühsen
d286d5408b Fix testenv/Test--rejected-log.py
* testenv/Test--rejected-log.py: Add missing tabs in expected output
2016-04-11 15:24:04 +02:00
Tim Rühsen
9883f9fb10 Fail python tests when post_hook errors
* testenv/test/base_test.py (__exit__): Return self.tests_passed
  (__test_cleanup): Set self.tests_passed to False on exception
2016-04-11 15:23:38 +02:00
Darshit Shah
d26377053d Print the fingerprint instead of the raw pointer in debugging message
* src/metalink.c (retrieve_from_metalink): Fix debug message to print the
fingerprint instead of a pointer.

* Do not delete the ChangeLog file since it is required by the Makefile
and breaks compilation
2016-03-29 15:09:04 +02:00
Darshit Shah
722675553c Revert "Print the fingerprint instead of the raw pointer in debugging message"
This reverts commit b916595168.
2016-03-29 15:07:29 +02:00
Tim Rühsen
281ad7dfb9 Fixed URLs and references in wget.texi
* wget.texi: Replace server.com by example.com,
  replace ftp://wuarchive.wustl.edu by https://example.com,
  use HTTPS instead of HTTP where possible,
  fix list archive reference,
  remove reference to wget-notify@addictivecode.org,
  change bugtracker URL to bugtracker on Savannah,
  replace yoyodyne.com by example.com,
  fix URL to VMS port
2016-03-28 18:33:33 +02:00
Giuseppe Scrivano
f3e63f0071 * metalink.c (retrieve_from_metalink): Fix typo 2016-03-25 16:46:39 +01:00
Giuseppe Scrivano
b916595168 Print the fingerprint instead of the raw pointer in debugging message
* src/metalink.c (retrieve_from_metalink): Fix debug message to print the
fingerprint instead of a pointer.
2016-03-25 16:23:19 +01:00
Tim Rühsen
76ef65b23c Add options --bind-dns-address and --dns-servers
* README.checkout: Add description for libares
* configure.ac: Add check for libares
* doc/wget.texi: Add docs for the new options
* src/build_info.c.in: Add +/-cares for --version output
* src/host.c:
  (merge_address_lists): New static function
  (address_list_from_hostent): New static function
  (wait_ares): New static function
  (callback): New static function
  (lookup_host): Add libares resolver code
* src/init.c: Add new options,
  (cleanup): Add cleanup code
* src/main.c: Add global libares channel variable
  (cmdline_option option_data): Add new options
  (print_help): Add short descriptions
  (main): Add libares init code
* src/options.h (struct options): Add option members

The new options allow to specify alternative DNS servers and
an alternate packet route for the resolver packets.
Wget has to built with libares, enabled at configure time by
./configure --with-cares.
2016-03-23 09:26:22 +01:00
Tim Rühsen
d7726f8a13 Fix SNI server names with trailing dot(s)
* src/gnutls.c (ssl_connect_wget, ssl_check_certificate): Fix SNI server name
* src/openssl.c (ssl_connect_wget, ssl_check_certificate): Fix SNI server name

Fixes #47408
2016-03-16 11:23:51 +01:00
Tim Rühsen
598445ebd1 Fix links to original Robots Exclusion Standard
* doc/wget.texi: Fix links
2016-03-10 16:20:05 +01:00
Darshit Shah
7cb9efa668 Fix assertion in Progress bar
* src/progress.c (create_image): Fix off-by-one error in assert()
    statement for progress bar width.
    Reported-By: Gisle Vanem <gvanem@yahoo.no>
2016-03-05 13:27:46 +01:00
Giuseppe Scrivano
44aedd8321 src/url.c: fix make syntax-check 2016-03-03 09:40:39 +01:00
Maks Orlovich
c28f51aadf Parse <img srcset> attributes, they have image URLs.
* src/convert.h: Add link_noquote_html_p to permit rewriting URLs deep
                 inside attributes without adding extraneous quoting
* src/convert.c (convert_links): Honor link_noquote_html_p
* src/html_url.c (tag_handle_img): New function. Add srcset parsing.
2016-03-03 09:38:45 +01:00
Darshit Shah
7099f48998 Sanitize value sent to memset to prevent SEGFAULT 2016-03-01 08:11:13 +01:00
Darshit Shah
75e5be7aad Update documentation about bahviour of -c
* docs/wget.texi: -c will restart download from scratch if server
    does not support RANGE.

    Reported-By: David Chavez
    http://stackoverflow.com/questions/30147332/unexpected-behavior-of-wget
2016-03-01 08:10:59 +01:00
Tim Rühsen
100da11312 Fix writing WARC-Target-URI value
src/warc.c: Add function warc_write_header_uri(),
            Use it for creating WARC-Target-URI

Fixes #47281
2016-02-27 23:08:28 +01:00
Darshit Shah
cceb5932b4 Remove pointer to unused Mailing List
* MAILING-LISTS: Remove pointer to old, unused mailing list for bug
    reports
2016-02-13 01:39:03 +01:00
Tim Rühsen
cacac6f996 Retain value of errno in logprintf(), logputs() even better
* src/log.c (logprintf,logputs): Save&Restore value of errno

Reported-by: Gisle Vanem <gvanem@yahoo.no>
2016-02-11 10:53:02 +01:00
Tim Rühsen
3056617e9c Retain value of errno in logprintf()
* src/log.c (logprintf): Save&Restore value of errno

Reported-by: Gisle Vanem <gvanem@yahoo.no>
2016-02-10 15:28:10 +01:00
Tim Rühsen
c190677cab Set AM_SILENT_RULES to yes by default
* configure.ac: Set AM_SILENT_RULES to yes by default
2016-02-01 21:10:33 +01:00
Ander Juaristi
4c2dc5010f Enforce 'RejectHeader' rule in tests
* server/http/http_server.py (_Handler.RejectHeader): enforce
   'RejectHeader' rule.
2016-02-01 20:48:00 +01:00
Tim Rühsen
b30500f0f4 Fix Test-iri-forced-remote
* tests/Test-iri-forced-remote.px: Fix encodings
2015-12-20 21:32:06 +01:00
Eli Zaretskii
59b920874d Support non-ASCII URLs
* src/url.c [HAVE_ICONV]: Include iconv.h and langinfo.h.
(convert_fname): New function.
[HAVE_ICONV]: Convert file name from remote encoding to local
encoding.
(url_file_name): Call convert_fname.
(filechr_table): Don't consider bytes in 128..159 as control
characters.

* tests/Test-ftp-iri.px: Fix the expected file name to match the
new file-name recoding.  State the remote encoding explicitly on
the Wget command line.

* NEWS: Mention the URI recoding when built with libiconv.
2015-12-18 20:54:39 +01:00
Giuseppe Scrivano
9a6e63bee9 * NEWS: Prepare new development cycle 2015-12-18 11:29:59 +01:00
Tim Rühsen
cbbeca2af4 Cleanup code
* src/iri.c (do_conversion): Code cleanup
2015-12-17 21:01:50 +01:00
Eli Zaretskii
93c1517c40 Set URI encoding when redirected
* src/retr.c (retrieve_url): Set URI on redirection
2015-12-17 15:27:43 +01:00
Tim Rühsen
bf5d7e9236 Remove requesting X/Open 5, POSIX 1995
* src/sysdep.h: Remove #define _XOPEN_SOURCE 500
2015-12-17 12:11:53 +01:00
Eli Zaretskii
94d9b68db9 Avoid hanging on MS-Windows when invoked with --connect-timeout
* src/connect.c (connect_to_ip) [WIN32]: Don't call fd_close if
the connection timed out, to avoid hanging.
2015-12-16 15:06:45 +01:00
Tim Rühsen
be7d19f478 Fix iconv conversion
* src/iri.c: Kick out the last converted character from iconv()

Thanks to Eli Zaretskii <eliz@gnu.org> for suggesting the fix.
Reported-by: "Andries E. Brouwer" <Andries.Brouwer@cwi.nl>
2015-12-15 10:55:41 +01:00
Tim Rühsen
358a3c330f Let Test-k survive on CygWin and Windows
* tests/Test-k.px: Use --restrict-file-names for CygWin/Windows
  filename requirements.
2015-12-14 09:36:40 +01:00
Ander Juaristi
478a584609 Fix leak in HSTS code
* src/hsts.c (hsts_store_open): close fp if open.
2015-12-13 16:10:16 +01:00
Ander Juaristi
994c4dcce7 Remove unused variable in ftp code
* src/ftp.c (getftp): fix compiler warning for unused variable.
2015-12-13 16:06:53 +01:00
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
166 changed files with 8851 additions and 3155 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

View File

@@ -23,15 +23,6 @@ Gmane archives conveniently include messages from both the current
list, and the previous one. Messages also show up in the Gmane archives
sooner than they do at `lists.gnu.org'.
Bug Notices List
----------------
Additionally, there is the <wget-notify@addictivecode.org> mailing
list. This is a non-discussion list that receives bug report
notifications from the bug-tracker. To subscribe to this list, send an
email to <wget-notify-join@addictivecode.org>, or visit
`http://addictivecode.org/mailman/listinfo/wget-notify'.
Obsolete Lists
--------------

69
NEWS
View File

@@ -1,12 +1,75 @@
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.18
* By default, on server redirects to a FTP resource, use the original
URL to get the local file name. Close CVE-2016-4971. This
introduces a backward-incompatibility for HTTP->FTP redirects and
any script that relies on the old behaviour must use
--trust-server-names.
* Check the HSTS file is not world-writable before using it.
* Parse <img srcset> attributes on a recursive download.
* Fix problem with SNI server names having trailing dot(s)
* New options --bind-dns-address and --dns-servers.
* When Wget is built with libiconv, it now converts non-ASCII URIs to
the locale's codeset when it creates files. The encoding of the
remote files and URIs is taken from --remote-encoding, defaulting to
UTF-8. The result is that non-ASCII URIs and files downloaded via
HTTP/HTTPS and FTP will have names on the local filesystem that
correspond to their remote names.
* 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 +177,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,19 @@ 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
"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'".
test suite written in perl and python (see below). To execute all the tests
you need libwww-perl and libio-socket-ssl-perl perl library.
GNU/Linux distros likely have these two libraries packaged.
If not, install them directly with "perl -MCPAN -e 'install Bundle::LWP'"[24].
If that fails then you most likely don't have the CPAN module installed.
First download [25]CPAN and [26]install it, then try again the above command.
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 +96,13 @@ 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.
* [48]libcares is needed to bind DNS resolving to a given IP address.
The command line options --dns-servers and --bind-dns-address are
only available when configured with --with-cares.
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 +124,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 +134,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 +208,7 @@ 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
48. http://c-ares.haxx.se/

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

@@ -57,6 +57,8 @@ AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([OS_TYPE], "$host_os",
[Define to be the name of the operating system.])
dnl Non-verbose make
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl
dnl Process External Libraries
@@ -70,11 +72,16 @@ dnl SSL: Configure SSL backend to use
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 C-Ares: Configure use of the c-ares library for DNS lookup
AC_ARG_WITH(cares, AS_HELP_STRING([--with-cares], [enable support for C-Ares DNS lookup.]), with_cares=$withval, with_cares=no)
dnl
dnl Process features
@@ -177,7 +184,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 +482,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
@@ -711,10 +746,36 @@ AS_IF([test "X$enable_pcre" != "Xno"],[
])
])
dnl
dnl Check for libcares (resolver library)
dnl
AS_IF([test "X$with_cares" == "Xyes"],[
PKG_CHECK_MODULES([CARES], libcares, [
CFLAGS="$CARES_CFLAGS $CFLAGS"
AC_CHECK_HEADER(ares.h, [
LIBS="$CARES_LIBS $LIBS"
AC_DEFINE([HAVE_LIBCARES], [1], [Define if libcares is available.])
RESOLVER_INFO="libcares, --bind-dns-address and --dns-servers available"
])
], [
AC_CHECK_HEADER(ares.h, [
AC_CHECK_LIB(cares, ares_set_local_ip4, [
LIBS="-lcares ${LIBS}"
AC_DEFINE([HAVE_LIBCARES], 1, [Define if libcares is available.])
RESOLVER_INFO="libcares, --bind-dns-address and --dns-servers available"
])
])
])
], [
RESOLVER_INFO="libc, --bind-dns-address and --dns-servers not available"
])
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 +804,7 @@ AC_MSG_NOTICE([Summary of build options:
Debugging: $ENABLE_DEBUG
Assertions: $ENABLE_ASSERTION
Valgrind: $VALGRIND_INFO
Metalink: $with_metalink
Resolver: $RESOLVER_INFO
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,10 @@ 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 $? > $@; \
if [ $? != 0 ]; then \
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" $? > $@; \
fi
#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
@@ -548,6 +571,27 @@ the local machine. @var{ADDRESS} may be specified as a hostname or IP
address. This option can be useful if your machine is bound to multiple
IPs.
@cindex bind DNS address
@cindex client DNS address
@cindex DNS IP address, client, DNS
@item --bind-dns-address=@var{ADDRESS}
[libcares only]
This address overrides the route for DNS requests. If you ever need to
circumvent the standard settings from /etc/resolv.conf, this option together
with @samp{--dns-servers} is your friend.
@var{ADDRESS} must be specified either as IPv4 or IPv6 address.
Wget needs to be built with libcares for this option to be available.
@cindex DNS server
@cindex DNS IP address, client, DNS
@item --dns-servers=@var{ADDRESSES}
[libcares only]
The given address(es) override the standard nameserver
addresses, e.g. as configured in /etc/resolv.conf.
@var{ADDRESSES} may be specified either as IPv4 or IPv6 addresses,
comma-separated.
Wget needs to be built with libcares for this option to be available.
@cindex retries
@cindex tries
@cindex number of tries
@@ -585,6 +629,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 +673,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.
@@ -665,13 +715,11 @@ Without @samp{-c}, the previous example would just download the remote
file to @file{ls-lR.Z.1}, leaving the truncated @file{ls-lR.Z} file
alone.
Beginning with Wget 1.7, if you use @samp{-c} on a non-empty file, and
it turns out that the server does not support continued downloading,
Wget will refuse to start the download from scratch, which would
effectively ruin existing contents. If you really want the download to
start from scratch, remove the file.
If you use @samp{-c} on a non-empty file, and the server does not support
continued downloading, Wget will restart the download from scratch and overwrite
the existing file entirely.
Also beginning with Wget 1.7, if you use @samp{-c} on a file which is of
Beginning with Wget 1.7, if you use @samp{-c} on a file which is of
equal size as the one on the server, Wget will refuse to download the
file and print an explanatory message. The same happens when the file
is smaller on the server than locally (presumably because it was changed
@@ -787,6 +835,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.
@@ -950,7 +1002,7 @@ specified in bytes (default), kilobytes (with @samp{k} suffix), or
megabytes (with @samp{m} suffix).
Note that quota will never affect downloading a single file. So if you
specify @samp{wget -Q10k ftp://wuarchive.wustl.edu/ls-lR.gz}, all of the
specify @samp{wget -Q10k https://example.com/ls-lR.gz}, all of the
@file{ls-lR.gz} will be downloaded. The same goes even when several
@sc{url}s are specified on the command-line. However, quota is
respected when retrieving either recursively, or from an input file.
@@ -1521,6 +1573,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.
@@ -1548,11 +1605,11 @@ users:
# @r{Log in to the server. This can be done only once.}
wget --save-cookies cookies.txt \
--post-data 'user=foo&password=bar' \
http://server.com/auth.php
http://example.com/auth.php
# @r{Now grab the page or pages we care about.}
wget --load-cookies cookies.txt \
-p http://server.com/interesting/article.php
-p http://example.com/interesting/article.php
@end group
@end example
@@ -1637,8 +1694,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 +1744,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}
@@ -1733,6 +1797,18 @@ system-specified locations, chosen at OpenSSL installation time.
Specifies a CRL file in @var{file}. This is needed for certificates
that have been revocated by the CAs.
@cindex SSL Public Key Pin
@item --pinnedpubkey=file/hashes
Tells wget to use the specified public key file (or hashes) to verify the peer.
This can be a path to a file which contains a single public key in PEM or DER
format, or any number of base64 encoded sha256 hashes preceded by ``sha256//''
and separated by ``;''
When negotiating a TLS or SSL connection, the server sends a certificate
indicating its identity. A public key is extracted from this certificate and if
it does not exactly match the public key(s) provided to this option, wget will
abort the connection before sending or receiving any data.
@cindex entropy, specifying source of
@cindex randomness, specifying source of
@item --random-file=@var{file}
@@ -1768,6 +1844,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 +2051,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 +2166,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
@@ -2397,11 +2592,11 @@ The @samp{-D} option allows you to specify the domains that will be
followed, thus limiting the recursion only to the hosts that belong to
these domains. Obviously, this makes sense only in conjunction with
@samp{-H}. A typical example would be downloading the contents of
@samp{www.server.com}, but allowing downloads from
@samp{images.server.com}, etc.:
@samp{www.example.com}, but allowing downloads from
@samp{images.example.com}, etc.:
@example
wget -rH -Dserver.com http://www.server.com/
wget -rH -Dexample.com http://www.example.com/
@end example
You can specify more than one address by separating them with a comma,
@@ -2641,7 +2836,7 @@ These links are not relative:
@example
<a href="/foo.gif">
<a href="/foo/bar.gif">
<a href="http://www.server.com/foo/bar.gif">
<a href="http://www.example.com/foo/bar.gif">
@end example
Using this option guarantees that recursive retrieval will not span
@@ -3511,7 +3706,7 @@ same directory structure the original has, with only one try per
document, saving the log of the activities to @file{gnulog}:
@example
wget -r http://www.gnu.org/ -o gnulog
wget -r https://www.gnu.org/ -o gnulog
@end example
@item
@@ -3519,7 +3714,7 @@ The same as the above, but convert the links in the downloaded files to
point to local files, so you can view the documents off-line:
@example
wget --convert-links -r http://www.gnu.org/ -o gnulog
wget --convert-links -r https://www.gnu.org/ -o gnulog
@end example
@item
@@ -3529,22 +3724,22 @@ sheets, are also downloaded. Also make sure the downloaded page
references the downloaded links.
@example
wget -p --convert-links http://www.server.com/dir/page.html
wget -p --convert-links http://www.example.com/dir/page.html
@end example
The @sc{html} page will be saved to @file{www.server.com/dir/page.html}, and
the images, stylesheets, etc., somewhere under @file{www.server.com/},
The @sc{html} page will be saved to @file{www.example.com/dir/page.html}, and
the images, stylesheets, etc., somewhere under @file{www.example.com/},
depending on where they were on the remote server.
@item
The same as the above, but without the @file{www.server.com/} directory.
The same as the above, but without the @file{www.example.com/} directory.
In fact, I don't want to have all those random server directories
anyway---just save @emph{all} those files under a @file{download/}
subdirectory of the current directory.
@example
wget -p --convert-links -nH -nd -Pdownload \
http://www.server.com/dir/page.html
http://www.example.com/dir/page.html
@end example
@item
@@ -3573,12 +3768,12 @@ wget -r -l2 -P/tmp ftp://wuarchive.wustl.edu/
@item
You want to download all the @sc{gif}s from a directory on an @sc{http}
server. You tried @samp{wget http://www.server.com/dir/*.gif}, but that
server. You tried @samp{wget http://www.example.com/dir/*.gif}, but that
didn't work because @sc{http} retrieval does not support globbing. In
that case, use:
@example
wget -r -l1 --no-parent -A.gif http://www.server.com/dir/
wget -r -l1 --no-parent -A.gif http://www.example.com/dir/
@end example
More verbose, but the effect is the same. @samp{-r -l1} means to
@@ -3594,7 +3789,7 @@ interrupted. Now you do not want to clobber the files already present.
It would be:
@example
wget -nc -r http://www.gnu.org/
wget -nc -r https://www.gnu.org/
@end example
@item
@@ -3602,7 +3797,7 @@ If you want to encode your own username and password to @sc{http} or
@sc{ftp}, use the appropriate @sc{url} syntax (@pxref{URL Format}).
@example
wget ftp://hniksic:mypassword@@unix.server.com/.emacs
wget ftp://hniksic:mypassword@@unix.example.com/.emacs
@end example
Note, however, that this usage is not advisable on multi-user systems
@@ -3639,7 +3834,7 @@ to recheck a site each Sunday:
@example
crontab
0 0 * * 0 wget --mirror http://www.gnu.org/ -o /home/me/weeklog
0 0 * * 0 wget --mirror https://www.gnu.org/ -o /home/me/weeklog
@end example
@item
@@ -3651,7 +3846,7 @@ would look like this:
@example
wget --mirror --convert-links --backup-converted \
http://www.gnu.org/ -o /home/me/weeklog
https://www.gnu.org/ -o /home/me/weeklog
@end example
@item
@@ -3664,13 +3859,13 @@ or @samp{application/xhtml+xml} to @file{@var{name}.html}.
@example
wget --mirror --convert-links --backup-converted \
--html-extension -o /home/me/weeklog \
http://www.gnu.org/
https://www.gnu.org/
@end example
Or, with less typing:
@example
wget -m -k -K -E http://www.gnu.org/ -o /home/me/weeklog
wget -m -k -K -E https://www.gnu.org/ -o /home/me/weeklog
@end example
@end itemize
@c man end
@@ -3777,14 +3972,14 @@ username and password.
Like all GNU utilities, the latest version of Wget can be found at the
master GNU archive site ftp.gnu.org, and its mirrors. For example,
Wget @value{VERSION} can be found at
@url{ftp://ftp.gnu.org/pub/gnu/wget/wget-@value{VERSION}.tar.gz}
@url{https://ftp.gnu.org/pub/gnu/wget/wget-@value{VERSION}.tar.gz}
@node Web Site, Mailing Lists, Distribution, Various
@section Web Site
@cindex web site
The official web site for GNU Wget is at
@url{http://www.gnu.org/software/wget/}. However, most useful
@url{https//www.gnu.org/software/wget/}. However, most useful
information resides at ``The Wget Wgiki'',
@url{http://wget.addictivecode.org/}.
@@ -3798,14 +3993,14 @@ information resides at ``The Wget Wgiki'',
The primary mailinglist for discussion, bug-reports, or questions
about GNU Wget is at @email{bug-wget@@gnu.org}. To subscribe, send an
email to @email{bug-wget-join@@gnu.org}, or visit
@url{http://lists.gnu.org/mailman/listinfo/bug-wget}.
@url{https://lists.gnu.org/mailman/listinfo/bug-wget}.
You do not need to subscribe to send a message to the list; however,
please note that unsubscribed messages are moderated, and may take a
while before they hit the list---@strong{usually around a day}. If
you want your message to show up immediately, please subscribe to the
list before posting. Archives for the list may be found at
@url{http://lists.gnu.org/pipermail/bug-wget/}.
@url{https://lists.gnu.org/archive/html/bug-wget/}.
An NNTP/Usenettish gateway is also available via
@uref{http://gmane.org/about.php,Gmane}. You can see the Gmane
@@ -3813,15 +4008,7 @@ archives at
@url{http://news.gmane.org/gmane.comp.web.wget.general}. Note that the
Gmane archives conveniently include messages from both the current
list, and the previous one. Messages also show up in the Gmane
archives sooner than they do at @url{lists.gnu.org}.
@unnumberedsubsec Bug Notices List
Additionally, there is the @email{wget-notify@@addictivecode.org} mailing
list. This is a non-discussion list that receives bug report
notifications from the bug-tracker. To subscribe to this list,
send an email to @email{wget-notify-join@@addictivecode.org},
or visit @url{http://addictivecode.org/mailman/listinfo/wget-notify}.
archives sooner than they do at @url{https://lists.gnu.org}.
@unnumberedsubsec Obsolete Lists
@@ -3833,7 +4020,7 @@ discussing patches to GNU Wget.
Messages from @email{wget@@sunsite.dk} are archived at
@itemize @tie{}
@item
@url{http://www.mail-archive.com/wget%40sunsite.dk/} and at
@url{https://www.mail-archive.com/wget%40sunsite.dk/} and at
@item
@url{http://news.gmane.org/gmane.comp.web.wget.general} (which also
continues to archive the current list, @email{bug-wget@@gnu.org}).
@@ -3862,7 +4049,7 @@ via IRC at @code{irc.freenode.org}, @code{#wget}. Come check it out!
@c man begin BUGS
You are welcome to submit bug reports via the GNU Wget bug tracker (see
@url{http://wget.addictivecode.org/BugTracker}).
@url{https://savannah.gnu.org/bugs/?func=additem&group=wget}).
Before actually submitting a bug report, please try to follow a few
simple guidelines.
@@ -3879,7 +4066,7 @@ Lists}).
@item
Try to repeat the bug in as simple circumstances as possible. E.g. if
Wget crashes while downloading @samp{wget -rl0 -kKE -t5 --no-proxy
http://yoyodyne.com -o /tmp/log}, you should try to see if the crash is
http://example.com -o /tmp/log}, you should try to see if the crash is
repeatable, and if will occur with a simpler set of options. You might
even try to start the download at the page where the crash occurred to
see if that page somehow triggered the crash.
@@ -3944,7 +4131,7 @@ Windows-related features might look at them.
Support for building on MS-DOS via DJGPP has been contributed by Gisle
Vanem; a port to VMS is maintained by Steven Schweda, and is available
at @url{http://antinode.org/}.
at @url{https://antinode.info/dec/sw/wget.html}.
@node Signals, , Portability, Various
@section Signals
@@ -4022,23 +4209,23 @@ download an individual page. Because of that, Wget honors RES when
downloading recursively. For instance, when you issue:
@example
wget -r http://www.server.com/
wget -r http://www.example.com/
@end example
First the index of @samp{www.server.com} will be downloaded. If Wget
First the index of @samp{www.example.com} will be downloaded. If Wget
finds that it wants to download more documents from that server, it will
request @samp{http://www.server.com/robots.txt} and, if found, use it
request @samp{http://www.example.com/robots.txt} and, if found, use it
for further downloads. @file{robots.txt} is loaded only once per each
server.
Until version 1.8, Wget supported the first version of the standard,
written by Martijn Koster in 1994 and available at
@url{http://www.robotstxt.org/wc/norobots.html}. As of version 1.8,
@url{http://www.robotstxt.org/robotstxt.html}. As of version 1.8,
Wget has supported the additional directives specified in the internet
draft @samp{<draft-koster-robots-00.txt>} titled ``A Method for Web
Robots Control''. The draft, which has as far as I know never made to
an @sc{rfc}, is available at
@url{http://www.robotstxt.org/wc/norobots-rfc.txt}.
@url{http://www.robotstxt.org/norobots-rfc.txt}.
This manual no longer includes the text of the Robot Exclusion Standard.
@@ -4096,12 +4283,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 +4323,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 +4334,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 +4401,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 +4411,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 +4441,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 +4453,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 +4481,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 +4516,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 +4525,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

@@ -8,6 +8,10 @@ nls defined ENABLE_NLS
ntlm defined ENABLE_NTLM
opie defined ENABLE_OPIE
psl defined HAVE_LIBPSL
cares defined HAVE_LIBCARES
metalink defined HAVE_METALINK
gpgme defined HAVE_GPGME
ssl choice:
openssl defined HAVE_LIBSSL || defined HAVE_LIBSSL32

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.
@@ -369,7 +369,14 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
logprintf. */
int save_errno = errno;
if (sock >= 0)
fd_close (sock);
{
#ifdef WIN32
/* If the connection timed out, fd_close will hang in Gnulib's
close_fd_maybe_socket, inside the call to WSAEnumNetworkEvents. */
if (errno != ETIMEDOUT)
#endif
fd_close (sock);
}
if (print)
logprintf (LOG_NOTQUIET, _("failed: %s.\n"), strerror (errno));
errno = save_errno;

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
@@ -305,7 +308,7 @@ convert_links (const char *file, struct urlpos *links)
char *quoted_newname = local_quote_string (newname,
link->link_css_p);
if (link->link_css_p)
if (link->link_css_p || link->link_noquote_html_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);
@@ -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 || link->link_noquote_html_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:
@@ -326,7 +352,7 @@ convert_links (const char *file, struct urlpos *links)
char *newlink = link->url->url;
char *quoted_newlink = html_quote_string (newlink);
if (link->link_css_p)
if (link->link_css_p || link->link_noquote_html_p)
p = replace_plain (p, link->size, fp, newlink);
else if (!link->link_refresh_p)
p = replace_attr (p, link->size, fp, quoted_newlink);
@@ -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. */
@@ -67,6 +69,7 @@ struct urlpos {
unsigned int link_base_p :1; /* the url came from <base href=...> */
unsigned int link_inline_p :1; /* needed to render the page */
unsigned int link_css_p :1; /* the url came from CSS */
unsigned int link_noquote_html_p :1; /* from HTML, but doesn't need " */
unsigned int link_expect_html :1; /* expected to contain HTML */
unsigned int link_expect_css :1; /* expected to contain CSS */

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.

362
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"
@@ -235,24 +236,96 @@ print_length (wgint size, wgint start, bool authoritative)
logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
}
static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **);
static uerr_t ftp_get_listing (struct url *, 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
is non-NULL, the downloaded data will be written there as well. */
static uerr_t
getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
getftp (struct url *u, struct url *original_url,
wgint passed_expected_bytes, wgint *qtyread,
wgint restval, ccon *con, int count, wgint *last_expected_bytes,
FILE *warc_tmp)
{
int csock, dtsock, local_sock, res;
uerr_t err = RETROK; /* appease the compiler */
FILE *fp;
FILE *fp = NULL;
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,
@@ -996,7 +1189,7 @@ Error in server response, closing control connection.\n"));
{
bool exists = false;
struct fileinfo *f;
uerr_t _res = ftp_get_listing (u, con, &f);
uerr_t _res = ftp_get_listing (u, original_url, con, &f);
/* Set the DO_RETR command flag again, because it gets unset when
calling ftp_get_listing() and would otherwise cause an assertion
failure earlier on when this function gets repeatedly called
@@ -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 url *original_url, struct fileinfo *f,
ccon *con, char **local_file, bool force_full_retrieve)
{
int count, orig_lp;
wgint restval, len = 0, qtyread = 0;
@@ -1565,7 +1806,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
{
/* URL-derived file. Consider "-O file" name. */
xfree (con->target);
con->target = url_file_name (u, NULL);
con->target = url_file_name (opt.trustservernames || !original_url ? u : original_url, NULL);
if (!opt.output_document)
locf = con->target;
else
@@ -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
@@ -1681,8 +1924,8 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
/* If we are working on a WARC record, getftp should also write
to the warc_tmp file. */
err = getftp (u, len, &qtyread, restval, con, count, &last_expected_bytes,
warc_tmp);
err = getftp (u, original_url, len, &qtyread, restval, con, count,
&last_expected_bytes, warc_tmp);
if (con->csock == -1)
con->st &= ~DONE_CWD;
@@ -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,13 +2083,18 @@ 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;
}
/* Return the directory listing in a reusable format. The directory
is specifed in u->dir. */
static uerr_t
ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
ftp_get_listing (struct url *u, struct url *original_url, ccon *con,
struct fileinfo **f)
{
uerr_t err;
char *uf; /* url file name */
@@ -1856,7 +2115,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, original_url, NULL, con, NULL, false);
lf = xstrdup (con->target);
xfree (con->target);
con->target = old_target;
@@ -1879,8 +2138,9 @@ ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
return err;
}
static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *);
static uerr_t ftp_retrieve_glob (struct url *, ccon *, int);
static uerr_t ftp_retrieve_dirs (struct url *, struct url *,
struct fileinfo *, ccon *);
static uerr_t ftp_retrieve_glob (struct url *, struct url *, ccon *, int);
static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
static void freefileinfo (struct fileinfo *f);
@@ -1892,7 +2152,8 @@ static void freefileinfo (struct fileinfo *f);
If opt.recursive is set, after all files have been retrieved,
ftp_retrieve_dirs will be called to retrieve the directories. */
static uerr_t
ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
ftp_retrieve_list (struct url *u, struct url *original_url,
struct fileinfo *f, ccon *con)
{
static int depth = 0;
uerr_t err;
@@ -1901,6 +2162,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 +2242,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 +2314,10 @@ 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, original_url, f, con, NULL,
force_full_retrieve);
}
} /* opt.retr_symlinks */
break;
case FT_DIRECTORY:
@@ -2062,7 +2328,10 @@ 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, original_url, f, con, NULL,
force_full_retrieve);
}
break;
case FT_UNKNOWN:
logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
@@ -2127,7 +2396,7 @@ Already have correct symlink %s -> %s\n\n"),
/* We do not want to call ftp_retrieve_dirs here */
if (opt.recursive &&
!(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
err = ftp_retrieve_dirs (u, orig, con);
err = ftp_retrieve_dirs (u, original_url, orig, con);
else if (opt.recursive)
DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
depth, opt.reclevel));
@@ -2140,7 +2409,8 @@ Already have correct symlink %s -> %s\n\n"),
ftp_retrieve_glob on each directory entry. The function knows
about excluded directories. */
static uerr_t
ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
ftp_retrieve_dirs (struct url *u, struct url *original_url,
struct fileinfo *f, ccon *con)
{
char *container = NULL;
int container_size = 0;
@@ -2190,7 +2460,7 @@ Not descending to %s as it is excluded/not-included.\n"),
odir = xstrdup (u->dir); /* because url_set_dir will free
u->dir. */
url_set_dir (u, newdir);
ftp_retrieve_glob (u, con, GLOB_GETALL);
ftp_retrieve_glob (u, original_url, con, GLOB_GETALL);
url_set_dir (u, odir);
xfree (odir);
@@ -2249,14 +2519,15 @@ is_invalid_entry (struct fileinfo *f)
GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
directory. */
static uerr_t
ftp_retrieve_glob (struct url *u, ccon *con, int action)
ftp_retrieve_glob (struct url *u, struct url *original_url,
ccon *con, int action)
{
struct fileinfo *f, *start;
uerr_t res;
con->cmd |= LEAVE_PENDING;
res = ftp_get_listing (u, con, &start);
res = ftp_get_listing (u, original_url, con, &start);
if (res != RETROK)
return res;
/* First: weed out that do not conform the global rules given in
@@ -2352,7 +2623,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
if (start)
{
/* Just get everything. */
res = ftp_retrieve_list (u, start, con);
res = ftp_retrieve_list (u, original_url, start, con);
}
else
{
@@ -2368,7 +2639,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, original_url, NULL, con, NULL, false);
return res;
}
@@ -2388,8 +2659,8 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
of URL. Inherently, its capabilities are limited on what can be
encoded into a URL. */
uerr_t
ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
bool recursive, bool glob)
ftp_loop (struct url *u, struct url *original_url, char **local_file, int *dt,
struct url *proxy, bool recursive, bool glob)
{
ccon con; /* FTP connection */
uerr_t res;
@@ -2410,16 +2681,17 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
if (!*u->file && !recursive)
{
struct fileinfo *f;
res = ftp_get_listing (u, &con, &f);
res = ftp_get_listing (u, original_url, &con, &f);
if (res == RETROK)
{
if (opt.htmlify && !opt.spider)
{
struct url *url_file = opt.trustservernames ? u : original_url;
char *filename = (opt.output_document
? xstrdup (opt.output_document)
: (con.target ? xstrdup (con.target)
: url_file_name (u, NULL)));
: url_file_name (url_file, NULL)));
res = ftp_index (filename, u, f);
if (res == FTPOK && opt.verbose)
{
@@ -2464,11 +2736,13 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
/* ftp_retrieve_glob is a catch-all function that gets called
if we need globbing, time-stamping, recursion or preserve
permissions. Its third argument is just what we really need. */
res = ftp_retrieve_glob (u, &con,
res = ftp_retrieve_glob (u, original_url, &con,
ispattern ? GLOB_GLOBALL : GLOB_GETONE);
}
else
res = ftp_loop_internal (u, NULL, &con, local_file);
{
res = ftp_loop_internal (u, original_url, 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,15 +160,17 @@ 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);
uerr_t ftp_loop (struct url *, char **, int *, struct url *, bool, bool);
uerr_t ftp_loop (struct url *, struct url *, char **, int *, struct url *,
bool, bool);
uerr_t ftp_index (const char *, struct url *, struct fileinfo *);

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.
@@ -36,7 +36,9 @@ as that of the covered work. */
#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>
#include <xalloc.h>
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <sys/ioctl.h>
@@ -56,6 +58,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 +189,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 +224,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 +282,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 +417,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,24 +436,124 @@ 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;
}
static const char *
_sni_hostname(const char *hostname)
{
size_t len = strlen(hostname);
char *sni_hostname = xmemdup(hostname, len + 1);
/* Remove trailing dot(s) to fix #47408.
* Regarding RFC 6066 (SNI): The hostname is represented as a byte
* string using ASCII encoding without a trailing dot. */
while (len && sni_hostname[--len] == '.')
sni_hostname[len] = 0;
return sni_hostname;
}
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);
/* We set the server name but only if it's not an IP address. */
if (! is_valid_ip_address (hostname))
{
gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
strlen (hostname));
/* GnuTLS 3.4.x (x<=10) disrespects the length parameter, we have to construct a new string */
/* see https://gitlab.com/gnutls/gnutls/issues/78 */
const char *sni_hostname = _sni_hostname(hostname);
gnutls_server_name_set (session, GNUTLS_NAME_DNS, sni_hostname, strlen(sni_hostname));
xfree(sni_hostname);
}
gnutls_set_default_priority (session);
@@ -531,79 +648,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,11 +682,70 @@ 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;
}
static bool
pkp_pin_peer_pubkey (gnutls_x509_crt_t cert, const char *pinnedpubkey)
{
/* Scratch */
size_t len1 = 0, len2 = 0;
char *buff1 = NULL;
gnutls_pubkey_t key = NULL;
/* Result is returned to caller */
int ret = 0;
bool result = false;
/* if a path wasn't specified, don't pin */
if (NULL == pinnedpubkey)
return true;
if (NULL == cert)
return result;
/* Begin Gyrations to get the public key */
gnutls_pubkey_init (&key);
ret = gnutls_pubkey_import_x509 (key, cert, 0);
if (ret < 0)
goto cleanup; /* failed */
ret = gnutls_pubkey_export (key, GNUTLS_X509_FMT_DER, NULL, &len1);
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
goto cleanup; /* failed */
buff1 = xmalloc (len1);
len2 = len1;
ret = gnutls_pubkey_export (key, GNUTLS_X509_FMT_DER, buff1, &len2);
if (ret < 0 || len1 != len2)
goto cleanup; /* failed */
/* End Gyrations */
/* The one good exit point */
result = wg_pin_peer_pubkey (pinnedpubkey, buff1, len1);
cleanup:
if (NULL != key)
gnutls_pubkey_deinit (key);
xfree (buff1);
return result;
}
#define _CHECK_CERT(flag,msg) \
if (status & (flag))\
{\
@@ -637,6 +766,11 @@ ssl_check_certificate (int fd, const char *host)
him about problems with the server's certificate. */
const char *severity = opt.check_cert ? _("ERROR") : _("WARNING");
bool success = true;
bool pinsuccess = opt.pinnedpubkey == NULL;
/* The user explicitly said to not check for the certificate. */
if (opt.check_cert == CHECK_CERT_QUIET && pinsuccess)
return success;
err = gnutls_certificate_verify_peers2 (ctx->session, &status);
if (err < 0)
@@ -661,6 +795,7 @@ ssl_check_certificate (int fd, const char *host)
gnutls_x509_crt_t cert;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
const char *sni_hostname;
if ((err = gnutls_x509_crt_init (&cert)) < 0)
{
@@ -695,13 +830,23 @@ ssl_check_certificate (int fd, const char *host)
logprintf (LOG_NOTQUIET, _("The certificate has expired\n"));
success = false;
}
if (!gnutls_x509_crt_check_hostname (cert, host))
sni_hostname = _sni_hostname(host);
if (!gnutls_x509_crt_check_hostname (cert, sni_hostname))
{
logprintf (LOG_NOTQUIET,
_("The certificate's owner does not match hostname %s\n"),
quote (host));
quote (sni_hostname));
success = false;
}
xfree(sni_hostname);
pinsuccess = pkp_pin_peer_pubkey (cert, opt.pinnedpubkey);
if (!pinsuccess)
{
logprintf (LOG_ALWAYS, _("The public key does not match pinned public key!\n"));
success = false;
}
crt_deinit:
gnutls_x509_crt_deinit (cert);
}
@@ -712,5 +857,6 @@ ssl_check_certificate (int fd, const char *host)
}
out:
return opt.check_cert ? success : true;
/* never return true if pinsuccess fails */
return !pinsuccess ? false : (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.
@@ -65,6 +65,7 @@ as that of the covered work. */
#include "host.h"
#include "url.h"
#include "hash.h"
#include "ptimer.h"
#ifndef NO_ADDRESS
# define NO_ADDRESS NO_DATA
@@ -649,6 +650,112 @@ cache_remove (const char *host)
}
}
#ifdef HAVE_LIBCARES
#include <sys/select.h>
#include <ares.h>
extern ares_channel ares;
static struct address_list *
merge_address_lists (struct address_list *al1, struct address_list *al2)
{
int count = al1->count + al2->count;
/* merge al2 into al1 */
al1->addresses = xrealloc (al1->addresses, sizeof (ip_address) * count);
memcpy (al1->addresses + al1->count, al2->addresses, sizeof (ip_address) * al2->count);
al1->count = count;
address_list_delete (al2);
return al1;
}
static struct address_list *
address_list_from_hostent (struct hostent *host)
{
int count, i;
struct address_list *al = xnew0 (struct address_list);
for (count = 0; host->h_addr_list[count]; count++)
;
assert (count > 0);
al->addresses = xnew_array (ip_address, count);
al->count = count;
al->refcount = 1;
for (i = 0; i < count; i++)
{
ip_address *ip = &al->addresses[i];
ip->family = host->h_addrtype;
memcpy (IP_INADDR_DATA (ip), host->h_addr_list[i], ip->family == AF_INET ? 4 : 16);
}
return al;
}
/* Since GnuLib's select() (i.e. rpl_select()) cannot handle socket-numbers
* returned from C-ares, we must use the original select() from Winsock.
*/
#ifdef WINDOWS
#undef select
#endif
static void
wait_ares (ares_channel channel)
{
struct ptimer *timer = NULL;
if (opt.dns_timeout)
timer = ptimer_new ();
for (;;)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds, rc;
FD_ZERO (&read_fds);
FD_ZERO (&write_fds);
nfds = ares_fds (channel, &read_fds, &write_fds);
if (nfds == 0)
break;
if (timer)
{
double max = opt.dns_timeout - ptimer_measure (timer);
tv.tv_sec = (long) max;
tv.tv_usec = 1000000 * (max - (long) max);
tvp = ares_timeout (channel, &tv, &tv);
}
else
tvp = ares_timeout (channel, NULL, &tv);
rc = select (nfds, &read_fds, &write_fds, NULL, tvp);
if (rc == 0 && timer && ptimer_measure (timer) >= opt.dns_timeout)
ares_cancel (channel);
else
ares_process (channel, &read_fds, &write_fds);
}
}
static void
callback (void *arg, int status, int timeouts _GL_UNUSED, struct hostent *host)
{
struct address_list **al = (struct address_list **) arg;
if (!host || status != ARES_SUCCESS)
{
*al = NULL;
return;
}
*al = address_list_from_hostent (host);
}
#endif
/* Look up HOST in DNS and return a list of IP addresses.
This function caches its result so that, if the same host is passed
@@ -755,80 +862,112 @@ lookup_host (const char *host, int flags)
}
#ifdef ENABLE_IPV6
{
int err;
struct addrinfo hints, *res;
#ifdef HAVE_LIBCARES
if (ares)
{
struct address_list *al4;
struct address_list *al6;
xzero (hints);
hints.ai_socktype = SOCK_STREAM;
if (opt.ipv4_only)
hints.ai_family = AF_INET;
else if (opt.ipv6_only)
hints.ai_family = AF_INET6;
else
/* We tried using AI_ADDRCONFIG, but removed it because: it
misinterprets IPv6 loopbacks, it is broken on AIX 5.1, and
it's unneeded since we sort the addresses anyway. */
if (opt.ipv4_only || !opt.ipv6_only)
ares_gethostbyname (ares, host, AF_INET, callback, &al4);
if (opt.ipv6_only || !opt.ipv4_only)
ares_gethostbyname (ares, host, AF_INET6, callback, &al6);
wait_ares (ares);
if (al4 && al6)
al = merge_address_lists (al4, al6);
else if (al4)
al = al4;
else
al = al6;
}
else
#endif
{
int err;
struct addrinfo hints, *res;
xzero (hints);
hints.ai_socktype = SOCK_STREAM;
if (opt.ipv4_only)
hints.ai_family = AF_INET;
else if (opt.ipv6_only)
hints.ai_family = AF_INET6;
else
/* We tried using AI_ADDRCONFIG, but removed it because: it
misinterprets IPv6 loopbacks, it is broken on AIX 5.1, and
it's unneeded since we sort the addresses anyway. */
hints.ai_family = AF_UNSPEC;
if (flags & LH_BIND)
hints.ai_flags |= AI_PASSIVE;
if (flags & LH_BIND)
hints.ai_flags |= AI_PASSIVE;
#ifdef AI_NUMERICHOST
if (numeric_address)
{
/* Where available, the AI_NUMERICHOST hint can prevent costly
access to DNS servers. */
hints.ai_flags |= AI_NUMERICHOST;
timeout = 0; /* no timeout needed when "resolving"
if (numeric_address)
{
/* Where available, the AI_NUMERICHOST hint can prevent costly
access to DNS servers. */
hints.ai_flags |= AI_NUMERICHOST;
timeout = 0; /* no timeout needed when "resolving"
numeric hosts -- avoid setting up
signal handlers and such. */
}
}
#endif
err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);
if (err != 0 || res == NULL)
{
if (!silent)
logprintf (LOG_VERBOSE, _("failed: %s.\n"),
err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
return NULL;
}
al = address_list_from_addrinfo (res);
freeaddrinfo (res);
if (!al)
{
logprintf (LOG_VERBOSE,
_("failed: No IPv4/IPv6 addresses for host.\n"));
return NULL;
}
err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);
/* Reorder addresses so that IPv4 ones (or IPv6 ones, as per
--prefer-family) come first. Sorting is stable so the order of
the addresses with the same family is undisturbed. */
if (al->count > 1 && opt.prefer_family != prefer_none)
stable_sort (al->addresses, al->count, sizeof (ip_address),
opt.prefer_family == prefer_ipv4
? cmp_prefer_ipv4 : cmp_prefer_ipv6);
}
if (err != 0 || res == NULL)
{
if (!silent)
logprintf (LOG_VERBOSE, _ ("failed: %s.\n"),
err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
return NULL;
}
al = address_list_from_addrinfo (res);
freeaddrinfo (res);
}
if (!al)
{
logprintf (LOG_VERBOSE,
_ ("failed: No IPv4/IPv6 addresses for host.\n"));
return NULL;
}
/* Reorder addresses so that IPv4 ones (or IPv6 ones, as per
--prefer-family) come first. Sorting is stable so the order of
the addresses with the same family is undisturbed. */
if (al->count > 1 && opt.prefer_family != prefer_none)
stable_sort (al->addresses, al->count, sizeof (ip_address),
opt.prefer_family == prefer_ipv4
? cmp_prefer_ipv4 : cmp_prefer_ipv6);
#else /* not ENABLE_IPV6 */
{
struct hostent *hptr = gethostbyname_with_timeout (host, timeout);
if (!hptr)
{
if (!silent)
{
if (errno != ETIMEDOUT)
logprintf (LOG_VERBOSE, _("failed: %s.\n"),
host_errstr (h_errno));
else
logputs (LOG_VERBOSE, _("failed: timed out.\n"));
}
return NULL;
}
/* Do older systems have h_addr_list? */
al = address_list_from_ipv4_addresses (hptr->h_addr_list);
}
#ifdef HAVE_LIBCARES
if (ares)
{
ares_gethostbyname (ares, host, AF_INET, callback, &al);
wait_ares (ares);
}
else
#endif
{
struct hostent *hptr = gethostbyname_with_timeout (host, timeout);
if (!hptr)
{
if (!silent)
{
if (errno != ETIMEDOUT)
logprintf (LOG_VERBOSE, _ ("failed: %s.\n"),
host_errstr (h_errno));
else
logputs (LOG_VERBOSE, _ ("failed: timed out.\n"));
}
return NULL;
}
/* Do older systems have h_addr_list? */
al = address_list_from_ipv4_addresses (hptr->h_addr_list);
}
#endif /* not ENABLE_IPV6 */
/* Print the addresses determined by DNS lookup, but no more than

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.

819
src/hsts.c Normal file
View File

@@ -0,0 +1,819 @@
/* 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;
bool changed;
};
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>\t<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;
}
}
}
/*
* Test:
* - The file is a regular file (ie. not a symlink), and
* - The file is not world-writable.
*/
static bool
hsts_file_access_valid (const char *filename)
{
struct_stat st;
if (stat (filename, &st) == -1)
return false;
return !(st.st_mode & S_IWOTH) && S_ISREG (st.st_mode);
}
/* 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;
store->changed = true;
}
}
else
{
hsts_remove_entry (store, kh);
store->changed = true;
}
}
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);
store->changed = true;
}
else if (max_age > 0)
{
if (entry->max_age != max_age ||
entry->include_subdomains != include_subdomains)
{
/* 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;
entry->include_subdomains = include_subdomains;
store->changed = true;
}
}
/* 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);
if (result)
store->changed = true;
}
/* 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;
store = xnew0 (struct hsts_store);
store->table = hash_table_new (0, hsts_hash_func, hsts_cmp_func);
store->last_mtime = 0;
store->changed = false;
if (file_exists_p (filename))
{
if (hsts_file_access_valid (filename))
{
struct_stat st;
FILE *fp = fopen (filename, "r");
if (!fp || !hsts_read_database (store, fp, false))
{
/* abort! */
hsts_store_close (store);
xfree (store);
fclose (fp);
goto out;
}
if (fstat (fileno (fp), &st) == 0)
store->last_mtime = st.st_mtime;
fclose (fp);
}
else
{
/*
* If we're not reading the HSTS database,
* then by all means act as if HSTS was disabled.
*/
hsts_store_close (store);
xfree (store);
logprintf (LOG_NOTQUIET, "Will not apply HSTS. "
"The HSTS database must be a regular and non-world-writable file.\n");
}
}
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);
}
}
}
bool
hsts_store_has_changed (hsts_store_t store)
{
return (store ? store->changed : false);
}
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 */

54
src/hsts.h Normal file
View File

@@ -0,0 +1,54 @@
/* 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_has_changed (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.
@@ -55,6 +56,7 @@ typedef void (*tag_handler_t) (int, struct taginfo *, struct map_context *);
DECLARE_TAG_HANDLER (tag_find_urls);
DECLARE_TAG_HANDLER (tag_handle_base);
DECLARE_TAG_HANDLER (tag_handle_form);
DECLARE_TAG_HANDLER (tag_handle_img);
DECLARE_TAG_HANDLER (tag_handle_link);
DECLARE_TAG_HANDLER (tag_handle_meta);
@@ -104,7 +106,7 @@ static struct known_tag {
{ TAG_FORM, "form", tag_handle_form },
{ TAG_FRAME, "frame", tag_find_urls },
{ TAG_IFRAME, "iframe", tag_find_urls },
{ TAG_IMG, "img", tag_find_urls },
{ TAG_IMG, "img", tag_handle_img },
{ TAG_INPUT, "input", tag_find_urls },
{ TAG_LAYER, "layer", tag_find_urls },
{ TAG_LINK, "link", tag_handle_link },
@@ -182,7 +184,8 @@ static const char *additional_attributes[] = {
"name", /* used by tag_handle_meta */
"content", /* used by tag_handle_meta */
"action", /* used by tag_handle_form */
"style" /* used by check_style_attr */
"style", /* used by check_style_attr */
"srcset", /* used by tag_handle_img */
};
static struct hash_table *interesting_tags;
@@ -303,6 +306,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 +315,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 +339,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);
@@ -670,6 +676,88 @@ tag_handle_meta (int tagid _GL_UNUSED, struct taginfo *tag, struct map_context *
}
}
/* Handle the IMG tag. This requires special handling for the srcset attr,
while the traditional src/lowsrc/href attributes can be handled generically.
*/
static void
tag_handle_img (int tagid, struct taginfo *tag, struct map_context *ctx) {
int attrind;
char *srcset;
/* Use the generic approach for the attributes without special syntax. */
tag_find_urls(tagid, tag, ctx);
srcset = find_attr (tag, "srcset", &attrind);
if (srcset)
{
/* These are relative to the input text. */
int base_ind = ATTR_POS (tag,attrind,ctx);
int size = strlen (srcset);
/* These are relative to srcset. */
int offset, url_start, url_end;
/* Make sure to line up base_ind with srcset[0], not outside quotes. */
if (ctx->text[base_ind] == '"' || ctx->text[base_ind] == '\'')
++base_ind;
offset = 0;
while (offset < size)
{
bool has_descriptor = true;
/* Skip over initial whitespace and commas. Note there is no \v
in HTML5 whitespace. */
url_start = offset + strspn (srcset + offset, " \f\n\r\t,");
if (url_start == size)
return;
/* URL is any non-whitespace chars (including commas) - but with
trailing commas removed. */
url_end = url_start + strcspn (srcset + url_start, " \f\n\r\t");
while ((url_end - 1) > url_start && srcset[url_end - 1] == ',')
{
has_descriptor = false;
--url_end;
}
if (url_end > url_start)
{
char *url_text = strdupdelim (srcset + url_start,
srcset + url_end);
struct urlpos *up = append_url (url_text, base_ind + url_start,
url_end - url_start, ctx);
up->link_inline_p = 1;
up->link_noquote_html_p = 1;
xfree (url_text);
}
/* If the URL wasn't terminated by a , there may also be a descriptor
which we just skip. */
if (has_descriptor)
{
/* This is comma-terminated, except there may be one level of
parentheses escaping that. */
bool in_paren = false;
for (offset = url_end; offset < size; ++offset)
{
char c = srcset[offset];
if (c == '(')
in_paren = true;
else if (c == ')' && in_paren)
in_paren = false;
else if (c == ',' && !in_paren)
break;
}
}
else
offset = url_end;
}
}
}
/* Dispatch the tag handler appropriate for the tag we're mapping
over. See known_tags[] for definition of tag handlers. */
@@ -748,10 +836,12 @@ get_urls_html (const char *file, const char *url, bool *meta_disallow_follow,
map_html_tags (fm->content, fm->length, collect_tags_mapper, &ctx, flags,
NULL, interesting_attributes);
#ifdef ENABLE_IRI
/* Meta charset is only valid if there was no HTTP header Content-Type charset. */
/* This is true for HTTP 1.0 and 1.1. */
if (iri && !iri->content_encoding && meta_charset)
set_content_encoding (iri, meta_charset);
#endif
DEBUGP (("no-follow in %s: %d\n", file, ctx.nofollow));
if (meta_disallow_follow)

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.

2374
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,
@@ -142,6 +143,9 @@ static const struct {
{ "backups", &opt.backups, cmd_number },
{ "base", &opt.base_href, cmd_string },
{ "bindaddress", &opt.bind_address, cmd_string },
#ifdef HAVE_LIBCARES
{ "binddnsaddress", &opt.bind_dns_address, cmd_string },
#endif
{ "bodydata", &opt.body_data, cmd_string },
{ "bodyfile", &opt.body_file, cmd_string },
#ifdef HAVE_SSL
@@ -152,13 +156,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
@@ -171,6 +176,9 @@ static const struct {
{ "dirprefix", &opt.dir_prefix, cmd_directory },
{ "dirstruct", NULL, cmd_spec_dirstruct },
{ "dnscache", &opt.dns_cache, cmd_boolean },
#ifdef HAVE_LIBCARES
{ "dnsservers", &opt.dns_servers, cmd_string },
#endif
{ "dnstimeout", &opt.dns_timeout, cmd_time },
{ "domains", &opt.domains, cmd_vector },
{ "dotbytes", &opt.dot_bytes, cmd_bytes },
@@ -188,12 +196,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 +223,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 +233,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 +244,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 },
@@ -235,9 +260,15 @@ static const struct {
{ "passiveftp", &opt.ftp_pasv, cmd_boolean },
{ "passwd", &opt.ftp_passwd, cmd_string },/* deprecated*/
{ "password", &opt.passwd, cmd_string },
#ifdef HAVE_SSL
{ "pinnedpubkey", &opt.pinnedpubkey, cmd_string },
#endif
{ "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 +291,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 +388,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 +425,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 +477,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 +607,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 +965,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 +984,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 +1574,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 +1590,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 +1884,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 +1929,19 @@ cleanup (void)
xfree (opt.post_data);
xfree (opt.body_data);
xfree (opt.body_file);
xfree (opt.rejected_log);
#ifdef HAVE_LIBCARES
#include <ares.h>
{
extern ares_channel ares;
xfree (opt.bind_dns_address);
xfree (opt.dns_servers);
ares_destroy (ares);
ares_library_cleanup ();
}
#endif
#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.

142
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,27 +118,26 @@ 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))
{
logprintf (LOG_VERBOSE, _("Conversion from %s to UTF-8 isn't supported\n"),
quote (opt.locale));
logprintf (LOG_VERBOSE, _("Conversion from %s to %s isn't supported\n"),
quote (fromcode), quote (tocode));
*out = NULL;
return false;
}
/* 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;
@@ -145,13 +146,21 @@ do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen,
for (;;)
{
if (iconv (cd, &in, &inlen, out, &outlen) != (size_t)(-1))
if (iconv (cd, &in, &inlen, out, &outlen) != (size_t)(-1) &&
iconv (cd, NULL, NULL, out, &outlen) != (size_t)(-1))
{
*out = s;
*(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;
}
@@ -171,16 +180,10 @@ do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen,
}
else if (errno == E2BIG) /* Output buffer full */
{
char *new;
tooshort++;
done = len;
outlen = done + inlen * 2;
new = xmalloc (outlen + 1);
memcpy (new, s, done);
xfree (s);
s = new;
len = outlen;
len = outlen = done + inlen * 2;
s = xrealloc (s, outlen + 1);
*out = s + done;
}
else /* Weird, we got an unspecified error */
@@ -192,7 +195,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 +226,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 +334,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 +356,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 +408,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 +425,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,24 +43,24 @@ 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 */
extern struct iri dummy_iri;
#define parse_charset(str) (str, NULL)
#define parse_charset(str) NULL
#define find_locale() NULL
#define check_encoding_name(str) false
#define locale_to_utf8(str) (str)

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.
@@ -351,6 +351,7 @@ logputs (enum log_options o, const char *s)
{
FILE *fp;
FILE *warcfp;
int errno_save = errno;
check_redirect_output ();
if (o == LOG_PROGRESS)
@@ -358,10 +359,14 @@ logputs (enum log_options o, const char *s)
else
fp = get_log_fp ();
errno = errno_save;
if (fp == NULL)
return;
warcfp = get_warc_log_fp ();
errno = errno_save;
CHECK_VERBOSE (o);
FPUTS (s, fp);
@@ -373,6 +378,8 @@ logputs (enum log_options o, const char *s)
logflush ();
else
needs_flushing = true;
errno = errno_save;
}
struct logvprintf_state {
@@ -543,8 +550,10 @@ logprintf (enum log_options o, const char *fmt, ...)
va_list args;
struct logvprintf_state lpstate;
bool done;
int errno_saved = errno;
check_redirect_output ();
errno = errno_saved;
if (inhibit_logging)
return;
CHECK_VERBOSE (o);
@@ -561,6 +570,8 @@ logprintf (enum log_options o, const char *fmt, ...)
exit (WGET_EXIT_GENERIC_ERROR);
}
while (!done);
errno = errno_saved;
}
#ifdef ENABLE_DEBUG
@@ -598,11 +609,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>
@@ -78,6 +86,13 @@ as that of the covered work. */
struct iri dummy_iri;
#endif
#ifdef HAVE_LIBCARES
#include <ares.h>
ares_channel ares;
#else
void *ares;
#endif
struct options opt;
/* defined in version.c */
@@ -134,6 +149,74 @@ 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 && hsts_store_has_changed (hsts_store))
{
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);
@@ -178,6 +261,9 @@ static struct cmdline_option option_data[] =
{ "backups", 0, OPT_BOOLEAN, "backups", -1 },
{ "base", 'B', OPT_VALUE, "base", -1 },
{ "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
#ifdef HAVE_LIBCARES
{ "bind-dns-address", 0, OPT_VALUE, "binddnsaddress", -1 },
#endif
{ "body-data", 0, OPT_VALUE, "bodydata", -1 },
{ "body-file", 0, OPT_VALUE, "bodyfile", -1 },
{ IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
@@ -190,6 +276,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 },
@@ -202,6 +289,9 @@ static struct cmdline_option option_data[] =
{ "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
{ "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
{ "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
#ifdef HAVE_LIBCARES
{ "dns-servers", 0, OPT_VALUE, "dnsservers", -1 },
#endif
{ "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
{ "domains", 'D', OPT_VALUE, "domains", -1 },
{ "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
@@ -219,10 +309,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 +339,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 },
@@ -258,9 +365,13 @@ static struct cmdline_option option_data[] =
{ "parent", 0, OPT__PARENT, NULL, optional_argument },
{ "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
{ "password", 0, OPT_VALUE, "password", -1 },
{ IF_SSL ("pinnedpubkey"), 0, OPT_VALUE, "pinnedpubkey", -1 },
{ "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 +410,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 +452,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 +592,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 +605,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 +632,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"),
@@ -523,6 +643,12 @@ Download:\n"),
--spider don't download anything\n"),
N_("\
-T, --timeout=SECONDS set all timeout values to SECONDS\n"),
#ifdef HAVE_LIBCARES
N_("\
--dns-servers=ADDRESSES list of DNS servers to query (comma separated)\n"),
N_("\
--bind-dns-address=ADDRESS bind DNS resolver to ADDRESS (hostname or IP) on local host\n"),
#endif
N_("\
--dns-timeout=SECS set the DNS lookup timeout to SECS\n"),
N_("\
@@ -572,6 +698,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_("\
@@ -674,6 +806,11 @@ HTTPS (SSL/TLS) options:\n"),
--ca-directory=DIR directory where hash list of CAs is stored\n"),
N_("\
--crl-file=FILE file with bundle of CRLs\n"),
N_("\
--pinnedpubkey=FILE/HASHES Public key (PEM/DER) file, or any number\n\
of base64 encoded sha256 hashes preceded by\n\
\'sha256//\' and seperated by \';\', to verify\n\
peer against\n"),
#if defined(HAVE_LIBSSL) || defined(HAVE_LIBSSL32)
N_("\
--random-file=FILE file with random data for seeding the SSL PRNG\n"),
@@ -685,6 +822,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 +854,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 +904,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 +1037,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 +1055,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 +1071,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 +1158,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 +1417,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 +1447,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 +1478,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 +1569,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,15 +1787,72 @@ 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);
}
}
#ifdef HAVE_LIBCARES
if (opt.bind_dns_address || opt.dns_servers)
{
if (ares_library_init (ARES_LIB_INIT_ALL))
{
fprintf (stderr, _("Failed to init libcares\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
if (ares_init (&ares) != ARES_SUCCESS)
{
fprintf (stderr, _("Failed to init c-ares channel\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
if (opt.bind_dns_address)
{
struct in_addr a4;
#ifdef ENABLE_IPV6
struct in6_addr a6;
#endif
if (inet_pton (AF_INET, opt.bind_dns_address, &a4) == 1)
{
ares_set_local_ip4 (ares, ntohl (a4.s_addr));
}
#ifdef ENABLE_IPV6
else if (inet_pton (AF_INET6, opt.bind_dns_address, &a6) == 1)
{
ares_set_local_ip6 (ares, (unsigned char *) &a6);
}
#endif
else
{
fprintf (stderr, _("Failed to parse IP address '%s'\n"), opt.bind_dns_address);
exit (WGET_EXIT_GENERIC_ERROR);
}
}
if (opt.dns_servers)
{
int result;
if ((result = ares_set_servers_csv (ares, opt.dns_servers)) != ARES_SUCCESS)
{
fprintf (stderr, _("Failed to set DNS server(s) '%s' (%d)\n"), opt.dns_servers, result);
exit (WGET_EXIT_GENERIC_ERROR);
}
}
}
#endif
#ifdef __VMS
/* Set global ODS5 flag according to the specified destination (if
any), otherwise according to the current default device.
@@ -1645,6 +1887,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 +1921,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 +1943,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 +1974,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 +2064,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 ();

782
src/metalink.c Normal file
View File

@@ -0,0 +1,782 @@
/* 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 (("Verifying 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 %s\n", gpgsig->fpr));
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.
@@ -62,7 +62,7 @@ void
xsleep (double seconds)
{
#if defined(HAVE_USLEEP) && defined(HAVE_SLEEP)
if (seconds > 1000)
if (seconds >= 1)
{
/* Explained in utils.c. */
sleep (seconds);

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.
@@ -35,6 +35,7 @@ as that of the covered work. */
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <xalloc.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
@@ -292,10 +293,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 +335,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 */
};
@@ -498,6 +507,22 @@ ssl_connect_with_timeout_callback(void *arg)
ctx->result = SSL_connect(ctx->ssl);
}
static const char *
_sni_hostname(const char *hostname)
{
size_t len = strlen(hostname);
char *sni_hostname = xmemdup(hostname, len + 1);
/* Remove trailing dot(s) to fix #47408.
* Regarding RFC 6066 (SNI): The hostname is represented as a byte
* string using ASCII encoding without a trailing dot. */
while (len && sni_hostname[--len] == '.')
sni_hostname[len] = 0;
return sni_hostname;
}
/* Perform the SSL handshake on file descriptor FD, which is assumed
to be connected to an SSL server. The SSL handle provided by
OpenSSL is registered with the file descriptor FD using
@@ -507,7 +532,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,11 +545,16 @@ 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))
{
if (! SSL_set_tlsext_host_name (conn, hostname))
const char *sni_hostname = _sni_hostname(hostname);
long rc = SSL_set_tlsext_host_name (conn, sni_hostname);
xfree(sni_hostname);
if (rc == 0)
{
DEBUGP (("Failed to set TLS server-name indication."));
goto error;
@@ -532,6 +562,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 +588,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. */
@@ -631,6 +672,65 @@ static char *_get_rfc2253_formatted (X509_NAME *name)
return out ? out : xstrdup("");
}
/*
* Heavily modified from:
* https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
*/
static bool
pkp_pin_peer_pubkey (X509* cert, const char *pinnedpubkey)
{
/* Scratch */
int len1 = 0, len2 = 0;
char *buff1 = NULL, *temp = NULL;
/* Result is returned to caller */
bool result = false;
/* if a path wasn't specified, don't pin */
if (!pinnedpubkey)
return true;
if (!cert)
return result;
/* Begin Gyrations to get the subjectPublicKeyInfo */
/* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
/* https://groups.google.com/group/mailing.openssl.users/browse_thread
/thread/d61858dae102c6c7 */
len1 = i2d_X509_PUBKEY (X509_get_X509_PUBKEY (cert), NULL);
if (len1 < 1)
goto cleanup; /* failed */
/* https://www.openssl.org/docs/crypto/buffer.html */
buff1 = temp = OPENSSL_malloc (len1);
if (!buff1)
goto cleanup; /* failed */
/* https://www.openssl.org/docs/crypto/d2i_X509.html */
len2 = i2d_X509_PUBKEY (X509_get_X509_PUBKEY (cert), (unsigned char **) &temp);
/*
* These checks are verifying we got back the same values as when we
* sized the buffer. It's pretty weak since they should always be the
* same. But it gives us something to test.
*/
if ((len1 != len2) || !temp || ((temp - buff1) != len1))
goto cleanup; /* failed */
/* End Gyrations */
/* The one good exit point */
result = wg_pin_peer_pubkey (pinnedpubkey, buff1, len1);
cleanup:
/* https://www.openssl.org/docs/crypto/buffer.html */
if (NULL != buff1)
OPENSSL_free (buff1);
return result;
}
/* Verify the validity of the certificate presented by the server.
Also check that the "common name" of the server, as presented by
its certificate, corresponds to HOST. (HOST typically comes from
@@ -654,6 +754,7 @@ ssl_check_certificate (int fd, const char *host)
long vresult;
bool success = true;
bool alt_name_checked = false;
bool pinsuccess = opt.pinnedpubkey == NULL;
/* If the user has specified --no-check-cert, we still want to warn
him about problems with the server's certificate. */
@@ -663,6 +764,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 && pinsuccess)
return success;
cert = SSL_get_peer_certificate (conn);
if (!cert)
{
@@ -739,9 +844,12 @@ ssl_check_certificate (int fd, const char *host)
{
/* Test subject alternative names */
/* SNI hostname must not have a trailing dot */
const char *sni_hostname = _sni_hostname(host);
/* Do we want to check for dNSNAmes or ipAddresses (see RFC 2818)?
* Signal it by host_in_octet_string. */
ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (host);
ASN1_OCTET_STRING *host_in_octet_string = a2i_IPADDRESS (sni_hostname);
int numaltnames = sk_GENERAL_NAME_num (subjectAltNames);
int i;
@@ -776,7 +884,7 @@ ssl_check_certificate (int fd, const char *host)
if (0 <= ASN1_STRING_to_UTF8 (&name_in_utf8, name->d.dNSName))
{
/* Compare and check for NULL attack in ASN1_STRING */
if (pattern_match ((char *)name_in_utf8, host) &&
if (pattern_match ((char *)name_in_utf8, sni_hostname) &&
(strlen ((char *)name_in_utf8) ==
(size_t) ASN1_STRING_length (name->d.dNSName)))
{
@@ -797,9 +905,11 @@ ssl_check_certificate (int fd, const char *host)
logprintf (LOG_NOTQUIET,
_("%s: no certificate subject alternative name matches\n"
"\trequested host name %s.\n"),
severity, quote_n (1, host));
severity, quote_n (1, sni_hostname));
success = false;
}
xfree(sni_hostname);
}
if (alt_name_checked == false)
@@ -854,6 +964,13 @@ ssl_check_certificate (int fd, const char *host)
}
}
pinsuccess = pkp_pin_peer_pubkey (cert, opt.pinnedpubkey);
if (!pinsuccess)
{
logprintf (LOG_ALWAYS, _("The public key does not match pinned public key!\n"));
success = false;
}
if (success)
DEBUGP (("X509 certificate successfully verified and matches host %s\n",
@@ -861,13 +978,13 @@ 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;
/* never return true if pinsuccess fails */
return !pinsuccess ? false : (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? */
@@ -87,6 +99,11 @@ struct options
void *(*regex_compile_fun)(const char *); /* Function to compile a regex. */
bool (*regex_match_fun)(const void *, const char *); /* Function to match a string to a regex. */
#ifdef HAVE_LIBCARES
char *bind_dns_address;
char *dns_servers;
#endif
char **domains; /* See host.c */
char **exclude_domains;
bool dns_cache; /* whether we cache DNS lookups. */
@@ -165,6 +182,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 +194,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 +227,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 {
@@ -220,9 +241,18 @@ struct options
char *ca_cert; /* CA certificate file to use */
char *crl_file; /* file with CRLs */
char *pinnedpubkey; /* Public key (PEM/DER) file, or any number
of base64 encoded sha256 hashes preceded by
\'sha256//\' and seperated by \';\', to verify
peer against */
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 +269,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 +319,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,25 @@ 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);
assert (padding >= 0 && "Padding length became non-positive!");
padding = padding > 0 ? padding : 0;
memset (p, ' ', padding);
p += padding;
*p = '\0';
/* 2014-11-14 Darshit Shah <darnir@gmail.com>
@@ -1169,8 +1176,11 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
* from the release code since we do not want Wget to crash and burn when the
* assertion fails. Instead Wget should continue downloading and display a
* horrible and irritating progress bar that spams the screen with newlines.
*
* By default, all assertions are disabled in a Wget build and are enabled
* only with the --enable-assert configure option.
*/
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
@@ -1188,8 +1198,6 @@ display_image (char *buf)
static void
bar_set_params (char *params)
{
char *term = getenv ("TERM");
if (params)
{
char *param = strtok (params, ":");
@@ -1209,12 +1217,6 @@ bar_set_params (char *params)
dots. */
|| !isatty (fileno (stderr))
#endif
/* Normally we don't depend on terminal type because the
progress bar only uses ^M to move the cursor to the
beginning of line, which works even on dumb terminals. But
Jamie Zawinski reports that ^M and ^H tricks don't work in
Emacs shell buffers, and only make a mess. */
|| (term && 0 == strcmp (term, "emacs"))
)
&& !current_impl_locked)
{

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,17 +232,21 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
struct iri *i = iri_new ();
#define COPYSTR(x) (x) ? xstrdup(x) : NULL;
FILE *rejectedlog = NULL; /* Don't write a rejected log. */
/* Duplicate pi struct if not NULL */
if (pi)
{
#define COPYSTR(x) (x) ? xstrdup(x) : NULL;
i->uri_encoding = COPYSTR (pi->uri_encoding);
i->content_encoding = COPYSTR (pi->content_encoding);
i->utf8_encode = pi->utf8_encode;
#undef COPYSTR
}
#ifdef ENABLE_IRI
else
set_uri_encoding (i, opt.locale, true);
#undef COPYSTR
#endif
queue = url_queue_new ();
blacklist = make_string_hash_table (0);
@@ -243,6 +257,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 +287,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 +320,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 +448,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 +470,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 +513,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 +551,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 +568,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 +603,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 +612,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 +629,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 +638,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 +658,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 +671,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 +703,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 +714,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 +757,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 +796,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 +807,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
@@ -807,14 +830,19 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
if (redirection_count)
oldrec = glob = false;
result = ftp_loop (u, &local_file, dt, proxy_url, recursive, glob);
result = ftp_loop (u, orig_parsed, &local_file, dt, proxy_url,
recursive, glob);
recursive = oldrec;
/* There is a possibility of having HTTP being redirected to
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;
@@ -845,11 +873,15 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
xfree (mynewloc);
mynewloc = construced_newloc;
/* Reset UTF-8 encoding state, keep the URI encoding and reset
#ifdef ENABLE_IRI
/* Reset UTF-8 encoding state, set the URI encoding and reset
the content encoding. */
iri->utf8_encode = opt.enable_iri;
if (opt.encoding_remote)
set_uri_encoding (iri, opt.encoding_remote, true);
set_content_encoding (iri, NULL);
xfree (iri->orig_url);
#endif
/* Now, see if this new location makes sense. */
newloc_parsed = url_parse (mynewloc, &up_error_code, iri, true);
@@ -941,7 +973,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 +1016,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
bail:
if (register_status)
inform_exit_status (result);
return result;
}
@@ -1019,6 +1052,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;
}
@@ -1035,10 +1069,12 @@ retrieve_from_file (const char *file, bool html, int *count)
if (dt & TEXTHTML)
html = true;
#ifdef ENABLE_IRI
/* If we have a found a content encoding, use it.
* ( == is okay, because we're checking for identical object) */
if (iri->content_encoding != opt.locale)
set_uri_encoding (iri, iri->content_encoding, false);
#endif
/* Reset UTF-8 encode status */
iri->utf8_encode = opt.enable_iri;
@@ -1074,12 +1110,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 +1304,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.
@@ -68,9 +68,6 @@ as that of the covered work. */
#ifdef NAMESPACE_TWEAKS
/* Request the "Unix 98 compilation environment". */
#define _XOPEN_SOURCE 500
#endif /* NAMESPACE_TWEAKS */
@@ -146,16 +143,6 @@ int snprintf (char *str, size_t count, const char *fmt, ...);
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
#endif
/* Some systems (Linux libc5, "NCR MP-RAS 3.0", and others) don't
provide MAP_FAILED, a symbolic constant for the value returned by
mmap() when it doesn't work. Usually, this constant should be -1.
This only makes sense for files that use mmap() and include
sys/mman.h *before* sysdep.h, but doesn't hurt others. */
#ifndef MAP_FAILED
# define MAP_FAILED ((void *) -1)
#endif
/* Enable system fnmatch only on systems where fnmatch.h is usable.
If the fnmatch on your system is buggy, undef this symbol and a
replacement implementation will be used instead. */

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 */

208
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.
@@ -43,6 +43,11 @@ as that of the covered work. */
#include "host.h" /* for is_valid_ipv6_address */
#include "c-strcase.h"
#if HAVE_ICONV
#include <iconv.h>
#include <langinfo.h>
#endif
#ifdef __VMS
#include "vms.h"
#endif /* def __VMS */
@@ -78,6 +83,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 +173,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 +193,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 +206,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 +731,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 +1358,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 +1369,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,25 +1387,25 @@ 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 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1381,10 +1415,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 +1430,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 +1456,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)
@@ -1493,6 +1536,82 @@ append_uri_pathel (const char *b, const char *e, bool escaped,
append_null (dest);
}
static char *
convert_fname (char *fname)
{
char *converted_fname = fname;
#if HAVE_ICONV
const char *from_encoding = opt.encoding_remote;
const char *to_encoding = opt.locale;
iconv_t cd;
size_t len, done, inlen, outlen;
char *s;
const char *orig_fname = fname;
/* Defaults for remote and local encodings. */
if (!from_encoding)
from_encoding = "UTF-8";
if (!to_encoding)
to_encoding = nl_langinfo (CODESET);
cd = iconv_open (to_encoding, from_encoding);
if (cd == (iconv_t)(-1))
logprintf (LOG_VERBOSE, _("Conversion from %s to %s isn't supported\n"),
quote (from_encoding), quote (to_encoding));
else
{
inlen = strlen (fname);
len = outlen = inlen * 2;
converted_fname = s = xmalloc (outlen + 1);
done = 0;
for (;;)
{
if (iconv (cd, &fname, &inlen, &s, &outlen) != (size_t)(-1)
&& iconv (cd, NULL, NULL, &s, &outlen) != (size_t)(-1))
{
*(converted_fname + len - outlen - done) = '\0';
iconv_close(cd);
DEBUGP (("Converted file name '%s' (%s) -> '%s' (%s)\n",
orig_fname, from_encoding, converted_fname, to_encoding));
xfree (orig_fname);
return converted_fname;
}
/* Incomplete or invalid multibyte sequence */
if (errno == EINVAL || errno == EILSEQ)
{
logprintf (LOG_VERBOSE,
_("Incomplete or invalid multibyte sequence encountered\n"));
xfree (converted_fname);
converted_fname = (char *)orig_fname;
break;
}
else if (errno == E2BIG) /* Output buffer full */
{
done = len;
len = outlen = done + inlen * 2;
converted_fname = xrealloc (converted_fname, outlen + 1);
s = converted_fname + done;
}
else /* Weird, we got an unspecified error */
{
logprintf (LOG_VERBOSE, _("Unhandled errno %d\n"), errno);
xfree (converted_fname);
converted_fname = (char *)orig_fname;
break;
}
}
DEBUGP (("Failed to convert file name '%s' (%s) -> '?' (%s)\n",
orig_fname, from_encoding, to_encoding));
}
iconv_close(cd);
#endif
return converted_fname;
}
/* Append to DEST the directory structure that corresponds the
directory part of URL's path. For example, if the URL is
http://server/dir1/dir2/file, this appends "/dir1/dir2".
@@ -1668,6 +1787,8 @@ url_file_name (const struct url *u, char *replaced_filename)
xfree (temp_fnres.base);
fname = convert_fname (fname);
/* Check the cases in which the unique extensions are not used:
1) Clobbering is turned off (-nc).
2) Retrieval with regetting.
@@ -1741,7 +1862,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 +1870,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 +2444,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.
@@ -31,14 +31,12 @@ as that of the covered work. */
#include "wget.h"
#include "sha256.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifdef HAVE_MMAP
# include <sys/mman.h>
#endif
#ifdef HAVE_PROCESS_H
# include <process.h> /* getpid() */
#endif
@@ -89,6 +87,18 @@ as that of the covered work. */
# define USE_SIGNAL_TIMEOUT
#endif
/* Some systems (Linux libc5, "NCR MP-RAS 3.0", and others) don't
provide MAP_FAILED, a symbolic constant for the value returned by
mmap() when it doesn't work. Usually, this constant should be -1.
This only makes sense for files that use mmap() and include
sys/mman.h *before* sysdep.h, but doesn't hurt others. */
#ifdef HAVE_MMAP
# include <sys/mman.h>
# ifndef MAP_FAILED
# define MAP_FAILED ((void *) -1)
# endif
#endif
#include "utils.h"
#include "hash.h"
@@ -336,7 +346,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 +1294,10 @@ free_vec (char **vec)
{
char **p = vec;
while (*p)
xfree (*p++);
{
xfree (*p);
p++;
}
xfree (vec);
}
}
@@ -2503,6 +2516,220 @@ 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 HAVE_SSL
/*
* Public key pem to der conversion
*/
static bool
wg_pubkey_pem_to_der (const char *pem, unsigned char **der, size_t *der_len)
{
char *stripped_pem, *begin_pos, *end_pos;
size_t pem_count, stripped_pem_count = 0, pem_len;
ssize_t size;
unsigned char *base64data;
*der = NULL;
*der_len = 0;
/* if no pem, exit. */
if (!pem)
return false;
begin_pos = strstr (pem, "-----BEGIN PUBLIC KEY-----");
if (!begin_pos)
return false;
pem_count = begin_pos - pem;
/* Invalid if not at beginning AND not directly following \n */
if (0 != pem_count && '\n' != pem[pem_count - 1])
return false;
/* 26 is length of "-----BEGIN PUBLIC KEY-----" */
pem_count += 26;
/* Invalid if not directly following \n */
end_pos = strstr (pem + pem_count, "\n-----END PUBLIC KEY-----");
if (!end_pos)
return false;
pem_len = end_pos - pem;
stripped_pem = xmalloc (pem_len - pem_count + 1);
/*
* Here we loop through the pem array one character at a time between the
* correct indices, and place each character that is not '\n' or '\r'
* into the stripped_pem array, which should represent the raw base64 string
*/
while (pem_count < pem_len) {
if ('\n' != pem[pem_count] && '\r' != pem[pem_count])
stripped_pem[stripped_pem_count++] = pem[pem_count];
++pem_count;
}
/* Place the null terminator in the correct place */
stripped_pem[stripped_pem_count] = '\0';
base64data = xmalloc (BASE64_LENGTH(stripped_pem_count));
size = base64_decode (stripped_pem, base64data);
if (size < 0) {
xfree (base64data); /* malformed base64 from server */
} else {
*der = base64data;
*der_len = (size_t) size;
}
xfree (stripped_pem);
return *der_len > 0;
}
/*
* Generic pinned public key check.
*/
bool
wg_pin_peer_pubkey (const char *pinnedpubkey, const char *pubkey, size_t pubkeylen)
{
struct file_memory *fm;
unsigned char *buf = NULL, *pem_ptr = NULL;
size_t size, pem_len;
bool pem_read;
bool result = false;
size_t pinkeylen;
ssize_t decoded_hash_length;
char *pinkeycopy, *begin_pos, *end_pos;
unsigned char *sha256sumdigest = NULL, *expectedsha256sumdigest = NULL;
/* if a path wasn't specified, don't pin */
if (!pinnedpubkey)
return true;
if (!pubkey || !pubkeylen)
return result;
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
if (strncmp (pinnedpubkey, "sha256//", 8) == 0) {
/* compute sha256sum of public key */
sha256sumdigest = xmalloc (SHA256_DIGEST_SIZE);
sha256_buffer (pubkey, pubkeylen, sha256sumdigest);
expectedsha256sumdigest = xmalloc (SHA256_DIGEST_SIZE + 1);
/* it starts with sha256//, copy so we can modify it */
pinkeylen = strlen (pinnedpubkey) + 1;
pinkeycopy = xmalloc (pinkeylen);
memcpy (pinkeycopy, pinnedpubkey, pinkeylen);
/* point begin_pos to the copy, and start extracting keys */
begin_pos = pinkeycopy;
do
{
end_pos = strstr (begin_pos, ";sha256//");
/*
* if there is an end_pos, null terminate,
* otherwise it'll go to the end of the original string
*/
if (end_pos)
end_pos[0] = '\0';
/* decode base64 pinnedpubkey, 8 is length of "sha256//" */
decoded_hash_length = base64_decode (begin_pos + 8, expectedsha256sumdigest);
/* if valid base64, compare sha256 digests directly */
if (SHA256_DIGEST_SIZE == decoded_hash_length &&
!memcmp (sha256sumdigest, expectedsha256sumdigest, SHA256_DIGEST_SIZE)) {
result = true;
break;
}
/*
* change back the null-terminator we changed earlier,
* and look for next begin
*/
if (end_pos) {
end_pos[0] = ';';
begin_pos = strstr (end_pos, "sha256//");
}
} while (end_pos && begin_pos);
xfree (sha256sumdigest);
xfree (expectedsha256sumdigest);
xfree (pinkeycopy);
return result;
}
/* fall back to assuming this is a file path */
fm = wget_read_file (pinnedpubkey);
if (!fm)
return result;
/* Check the file's size */
if (fm->length < 0 || fm->length > MAX_PINNED_PUBKEY_SIZE)
goto cleanup;
/*
* if the size of our certificate is bigger than the file
* size then it can't match
*/
size = (size_t) fm->length;
if (pubkeylen > size)
goto cleanup;
/* If the sizes are the same, it can't be base64 encoded, must be der */
if (pubkeylen == size) {
if (!memcmp (pubkey, fm->content, pubkeylen))
result = true;
goto cleanup;
}
/*
* Otherwise we will assume it's PEM and try to decode it
* after placing null terminator
*/
buf = xmalloc (size + 1);
memcpy (buf, fm->content, size);
buf[size] = '\0';
pem_read = wg_pubkey_pem_to_der ((const char *) buf, &pem_ptr, &pem_len);
/* if it wasn't read successfully, exit */
if (!pem_read)
goto cleanup;
/*
* if the size of our certificate doesn't match the size of
* the decoded file, they can't be the same, otherwise compare
*/
if (pubkeylen == pem_len && !memcmp (pubkey, pem_ptr, pubkeylen))
result = true;
cleanup:
xfree (buf);
xfree (pem_ptr);
wget_read_file_free (fm);
return result;
}
#endif /* HAVE_SSL */
#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,9 +32,15 @@ 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
#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
#endif
/* Macros that interface to malloc, but know about type sizes, and
cast the result to the appropriate type. The casts are not
necessary in standard C, but Wget performs them anyway for the sake
@@ -155,6 +161,13 @@ 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[];
#ifdef HAVE_SSL
/* Check pinned public key. */
bool wg_pin_peer_pubkey (const char *pinnedpubkey, const char *pubkey, size_t pubkeylen);
#endif
#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;
@@ -250,6 +246,22 @@ warc_write_header (const char *name, const char *value)
return warc_write_ok;
}
/* Writes a WARC header with a URI as value to the current WARC record.
This method may be run after warc_write_start_record and
before warc_write_block_from_file. */
static bool
warc_write_header_uri (const char *name, const char *value)
{
if (value)
{
warc_write_string (name);
warc_write_string (": <");
warc_write_string (value);
warc_write_string (">\r\n");
}
return warc_write_ok;
}
/* Copies the contents of DATA_IN to the WARC record.
Adds a Content-Length header to the WARC record.
Run this method after warc_write_header,
@@ -404,7 +416,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 +447,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 +552,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 +584,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 +743,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 +752,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 +835,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 +1004,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 +1107,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 +1237,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,12 +1302,13 @@ 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");
warc_write_header ("WARC-Target-URI", url);
warc_write_header_uri ("WARC-Target-URI", url);
warc_write_header ("Content-Type", "application/http;msgtype=request");
warc_write_date_header (timestamp_str);
warc_write_header ("WARC-Record-ID", record_uuid);
@@ -1382,18 +1392,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 +1423,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 +1441,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 +1480,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 +1524,6 @@ warc_write_response_record (char *url, char *timestamp_str,
response_uuid);
}
xfree (block_digest);
xfree (payload_digest);
return warc_write_ok;
}
@@ -1535,16 +1540,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 +1587,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 +1609,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,62 @@
# 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-missing-scheme-retval.py \
Test-pinnedpubkey-der-https.py \
Test-pinnedpubkey-der-no-check-https.py \
Test-pinnedpubkey-hash-https.py \
Test-pinnedpubkey-hash-no-check-fail-https.py \
Test-pinnedpubkey-pem-fail-https.py \
Test-pinnedpubkey-pem-https.py \
Test-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

@@ -97,6 +97,7 @@ Environment Variables:
the test suite will execute all the tests via this command.
If it is set to "1", valgrind memcheck is enabled with hard coded options.
This variable is set by ./configure --enable-valgrind-tests.
* SSL_TESTS: This must be set to run any https tests.
File Structure:
@@ -124,7 +125,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 +185,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,77 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
"""
This test ensures that Wget link conversion works also on HTTP error pages.
"""
############# File Definitions ###############################################
a_x_FileContent = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="/b/y.html"></a>
</body>
</html>
"""
a_x_LocalFileContent = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<a href="../b/y.html"></a>
</body>
</html>
"""
error_FileContent = '404 page content'
error_FileRules = {
'Response': 404 ,
'SendHeader': {
'Content-Length': len(error_FileContent),
'Content-Type': 'text/plain',
}
}
a_x_File = WgetFile ("a/x.html", a_x_FileContent)
robots_File = WgetFile ("robots.txt", '')
error_File = WgetFile ("b/y.html", error_FileContent, rules=error_FileRules)
B_File = WgetFile ("a/x.html", a_x_LocalFileContent)
WGET_OPTIONS = "--no-host-directories -r -l2 --convert-links --content-on-error"
WGET_URLS = [["a/x.html"]]
Files = [[a_x_File, robots_File, error_File]]
ExpectedReturnCode = 8
ExpectedDownloadedFiles = [B_File, robots_File, error_File]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode
}
err = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
).begin ()
exit (err)

View File

@@ -8,7 +8,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?"
@@ -40,7 +42,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test,

View File

@@ -8,7 +8,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?"
@@ -45,7 +47,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test,

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

@@ -0,0 +1,100 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
"""
This test executed Wget in recursive mode with a rejected log outputted.
"""
############# File Definitions ###############################################
mainpage = """
<html>
<head>
<title>Main Page</title>
</head>
<body>
<p>
Recurse to a <a href="http://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\tU_URL\tU_SCHEME\tU_HOST\tU_PORT\tU_PATH\tU_PARAMS\tU_QUERY\tU_FRAGMENT\tP_URL\tP_SCHEME\tP_HOST\tP_PORT\tP_PATH\tP_PARAMS\tP_QUERY\tP_FRAGMENT
BLACKLIST\thttp%3A//127.0.0.1%3A{{port}}/index.html\tSCHEME_HTTP\t127.0.0.1\t{{port}}\tindex.html\t\t\t\thttp%3A//127.0.0.1%3A{{port}}/secondpage.html\tSCHEME_HTTP\t127.0.0.1\t{{port}}\tsecondpage.html\t\t\t
ROBOTS\thttp%3A//127.0.0.1%3A{{port}}/dummy.txt\tSCHEME_HTTP\t127.0.0.1\t{{port}}\tdummy.txt\t\t\t\thttp%3A//127.0.0.1%3A{{port}}/thirdpage.html\tSCHEME_HTTP\t127.0.0.1\t{{port}}\tthirdpage.html\t\t\t
SPANNEDHOST\thttp%3A//no.such.domain/\tSCHEME_HTTP\tno.such.domain\t80\t\t\t\t\thttp%3A//127.0.0.1%3A{{port}}/thirdpage.html\tSCHEME_HTTP\t127.0.0.1\t{{port}}\tthirdpage.html\t\t\t
"""
dummyfile = "Don't care."
index_html = WgetFile ("index.html", mainpage)
secondpage_html = WgetFile ("secondpage.html", secondpage)
thirdpage_html = WgetFile ("thirdpage.html", thirdpage)
robots_txt = WgetFile ("robots.txt", robots)
dummy_txt = WgetFile ("dummy.txt", dummyfile)
log_csv = WgetFile ("log.csv", log)
WGET_OPTIONS = "-nd -r --rejected-log log.csv"
WGET_URLS = [["index.html"]]
Files = [[index_html, secondpage_html, thirdpage_html, robots_txt, dummy_txt]]
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [index_html, secondpage_html, thirdpage_html, robots_txt, log_csv]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode
}
err = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
).begin ()
exit (err)

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
This test executed Wget in Spider mode with recursive retrieval.
"""
TEST_NAME = "Recursive Spider"
############# File Definitions ###############################################
mainpage = """
<html>
@@ -97,7 +96,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -18,7 +18,6 @@ from misc.wget_file import WgetFile
considered 504 as a general Server Error, it would be a fatal failure and
Wget would request File1 only once.
"""
TEST_NAME = "504 Gateway Timeouts"
############# File Definitions ###############################################
File1 = """All happy families are alike;
Each unhappy family is unhappy in its own way"""
@@ -63,7 +62,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -7,7 +7,6 @@ from misc.wget_file import WgetFile
This test ensures that Wget parses the Content-Disposition header
correctly and creates the appropriate file when the said filename exists.
"""
TEST_NAME = "Content Disposition Clobber"
############# File Definitions ###############################################
File1 = "Teapot"
File2 = "The Teapot Protocol"
@@ -45,7 +44,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

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