208 Commits
v1.17 ... v1.19

Author SHA1 Message Date
Tim Rühsen
366d82f349 * src/utils.c: Move macro FMT_MAX_LENGTH into scope 2017-02-03 12:35:49 +01:00
Tim Rühsen
f2574e90b7 * src/utils.c: Fix -Wformat= warnings 2017-02-03 12:33:38 +01:00
Tim Rühsen
81b3aaf75c * src/gnutls.c: Fix -Wformat= warnings 2017-02-03 12:31:51 +01:00
Tim Rühsen
17d2f42a3d * src/iri.c: Remove unused macro IDNA_FLAGS 2017-02-03 12:28:37 +01:00
Tim Rühsen
638df40476 * src/iri.c: Remove use of __func__ macros 2017-02-03 12:28:05 +01:00
Tim Rühsen
00bafe72f1 * src/http.c: Fix -Wformat= warnings 2017-02-03 12:24:41 +01:00
Tim Rühsen
e777c01f43 * src/progress.c: Remove unused macro move_to_end 2017-02-03 12:18:14 +01:00
Tim Rühsen
3ba112ea57 * src/html-parse.c: Remove unused macro SKIP_NON_WS 2017-02-03 12:15:24 +01:00
Tim Rühsen
485fcfcc20 * src/hsts.c: Remove unused macro CHECK_EXPLICIT_PORT 2017-02-03 12:09:18 +01:00
Tim Rühsen
a5094731cd * src/hsts.c: Fix -Wformat= warnings 2017-02-03 12:08:08 +01:00
Tim Rühsen
3186eb2976 * src/hash.c: Explicitly convert float to int 2017-02-03 12:03:50 +01:00
Tim Rühsen
9947663af8 * src/ftp-ls.c: Fix -Wformat= warnings 2017-02-03 11:59:33 +01:00
Tim Rühsen
cfae085665 * src/ftp.c (ftp_retrieve_list): Add default to switch 2017-02-03 11:57:02 +01:00
Tim Rühsen
e69808256b * src/css-url.h: Remove redundant declaration 2017-02-03 11:53:28 +01:00
Tim Rühsen
11989ef669 * src/ftp.c: Fix -Wformat= warning 2017-02-03 11:52:08 +01:00
Tim Rühsen
5fceab6cb9 * src/http.c (test_parse_range_header): Fix constants 2017-02-03 10:32:42 +01:00
Dale R. Worley
d6eead1794 Improve documentation of --trust-server-names. 2017-02-02 12:10:43 +01:00
Tim Rühsen
d0e02a54ae * src/url.c (mkalldirs): Add newline to log message 2017-02-02 11:11:50 +01:00
Tim Rühsen
2e70409844 * src/cookies.c (check_domain_match): Add newline to DEBUG lines 2017-02-02 11:11:07 +01:00
Tim Rühsen
4734e8d4d7 * NEWS: update 2017-01-17 15:16:40 +01:00
Tim Rühsen
0fe8a5c40e * README.checkout: Link HTTPS where possible, update flex homepage 2017-01-17 14:25:15 +01:00
Tim Rühsen
1b9374ee59 * README.checkout: Fix libidn to libidn2 2017-01-17 14:07:16 +01:00
Tim Rühsen
6de24fe3c0 * src/iri.c: Use TR46 non-transitional for toASCII conversion 2017-01-13 15:53:03 +01:00
Tim Rühsen
0ab3d92c85 * src/main.c: Fix _Noreturn compiler warnings 2017-01-13 15:50:19 +01:00
Tim Rühsen
4cf8af84e0 * src/utils.c: Fix _Noreturn compiler warning 2017-01-13 15:49:05 +01:00
Tim Rühsen
42b8761cbc * src/init.c (setval_internal): Fix sign compare warning 2017-01-13 15:47:02 +01:00
Tim Rühsen
fd0f759597 Replace home-grown portability code by gnulib modules
* bootstrap.conf: Add intprops, inttypes, limits-h, signal-h,
  stat, sys_types
* src/ftp.c: Replace 'struct_stat' by 'struct stat'
* src/hsts.c: Likewise
* src/http.c: Likewise
* src/main.c: Likewise
* src/netrc.c: Likewise
* src/retr.c: Likewise
* src/url.c: Likewise
* src/utils.c: Likewise
* src/sysdep.h: Remove old portability code

Further portability issues should be addressed by gnulib.
2017-01-13 15:38:15 +01:00
Tim Rühsen
a384f5e2e9 Replace WGET_* m4 macros by gnulib modules
* bootstrap.conf: Add hostent, inet_ntop, nanosleep, utimens
* configure.ac: Remove WGET_STRUCT_UTIMBUF, WGET_FNMATCH,
  WGET_NANOSLEEP, WGET_POSIX_CLOCK, WGET_NSL_SOCKET
* m4/wget.m4: Likewise
* src/Makefile.am: Add $(LIB_NANOSLEEP) $(LIB_POSIX_SPAWN) to LDADD
* tests/Makefile.am: Likewise
* src/host.c (print_address): Use inet_ntop also for IPV4
2017-01-13 12:54:35 +01:00
Tim Rühsen
5ae1f37902 Remove libidn vulnerability work-around
* src/iri.c (_utf8_is_valid): Removed

Since we are using libidn2 for IDNs, we no longer need
this work-around.
2017-01-13 12:03:47 +01:00
Tim Rühsen
0eb4a21b6c * src/iri.c (idn_encode): Use TR46 transitional if available 2017-01-13 11:45:18 +01:00
Tim Rühsen
60dc3c21b2 * gnulibx: Update 2017-01-13 10:59:25 +01:00
Tim Rühsen
1a01a6b2d0 Fix previous commit 2427ca4ac0 2017-01-07 15:59:11 +01:00
vijeth-aradhya
2427ca4ac0 Fix http.c and ftp.c passwd logic error
* src/ftp.c (getftp): Fix password/user selection
* src/http.c (initialize_request): Likewise

Before, netrc password won over interactive
--ask-password but now --ask-password wins
after change of program logic

Fixes Issue #48811
2017-01-06 16:18:40 +01:00
Giuseppe Scrivano
42c2ce71bc * src/main.c (main): Add missing \n in error message 2016-12-31 17:11:01 +01:00
Giuseppe Scrivano
def133f26f Check that fd_set has not fds bigger than FD_SETSIZE
* src/connect.c: check that the fd is not bigger than FD_SETSIZE
  before using FD_SET.  An fd_set cannot hold fds bigger than
  FD_SETSIZE, causing out-of-bounds write to a buffer on the stack.

Reported by: Jann Horn <jannh@google.com>
2016-12-28 12:24:19 +01:00
Nikos Mavrogiannopoulos
b9ed06afd8 Avoid calling the gnutls priority functions multiple times
* src/gnutls.c (ssl_connect_wget): Call gnutls_set_default_priority()
  for --secure-protocol=auto (default).

The patch fixes a behavior that may have unintended side-effects in
certain gnutls versions. Instead use the default priorities when no
options are given.

Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
2016-12-20 14:48:31 +01:00
Tim Rühsen
1bdc20d774 Print debug message when skipping certain recursive downloads
* src/recur.c (retrieve_tree): Print debug message instead silently
  skipping recursive downloads.
2016-12-19 12:19:52 +01:00
Rahul Bedarkar
e4e9d3c1c8 Rename base64_{encode,decode} (trivial patch)
* src/http-ntlm.c: Rename base64_{encode,decode}
* src/http.c: Likewise
* src/utils.c: Likewise
* src/utils.h: Likewise

When statically linking with gnutls, we get definition clash error for
base64_encode which is also defined by gnutls.

To prevent definition clash, rename base64_{encode,decode}

Signed-off-by: Rahul Bedarkar <rahul.bedarkar@imgtec.com>
2016-12-14 15:52:52 +01:00
Tim Rühsen
dcdd618b18 Add support for psl_latest()
* configure.ac: Add check for psl_latest(),
  remove --with-psl-file
* src/cookies.c (check_domain_match): Use psl_latest() if available
2016-12-11 21:04:40 +01:00
Piotr Wajda
3c796b9a85 Respect -o parameter again
* log.c: don't choose log output dynamically when opt.lfilename is set

 Regression introduced by dd5c549f6a
 Reported-by: Dale R. Worley
2016-11-09 13:32:14 +01:00
Tim Rühsen
00ae9b4ee2 Move Wget from IDN2003 (libidn) to IDN2008 (libidn2)
* .travis.yml: Install libidn2-dev instead libidn11-dev.
* bootstrap.conf: Add modules libunistring-optional, unistr/base,
  unicase/tolower.
* configure.ac: Check for libidn2.
* src/Makefile.am: Add $(LTLIBUNISTRING) to LDADD.
* tests/Makefile.am: Set LDADD similar to LDADD in src/Makefile.am
* src/connect.c: Use libidn2 code instead of libidn.
* src/host.c: Likewise.
* src/iri.c: Likewise.
* src/iri.h: Likewise.
* src/options.h: Likewise.
* src/url.c: Likewise.
* src/url.h: Likewise.
* src/log.c: Fix C99 comment.

IDN2003 should not be used any more due to security concerns.
We use libunistring (resp. the unicode code from gnulib) for
lowercasing UTF-8 before we give data to libidn2.
TR#46 is missing, no support in libidn2 nor in libunistring.
2016-11-07 11:03:42 +01:00
Tim Rühsen
2242d5aee4 Use -O0 in contrib scripts
* contrib/check-hard: Use -O0 instead of -O2 to speed up script.
* contrib/travis-ci: Likewise.
2016-11-03 15:47:41 +01:00
Tim Rühsen
77a546348c Update gnulib 2016-11-03 13:28:17 +01:00
Tim Rühsen
be5517f98f * src/metalink.c: Fix typo 'suceeded' -> 'succeeded'
Reported-by: Göran Uddeborg <goeran@uddeborg.se>,
             Anders Jonsson <anders.jonsson@norsjovallen.se>
2016-10-22 22:21:39 +02:00
losgrandes
dd5c549f6a Fixes #45790: wget prints it's progress even when background
* src/log.c: Use tcgetpgrp(STDIN_FILENO) != getpgrp() to determine when to print to STD* or logfile.
  Deprecate log_request_redirect_output function.
  Use different file handles for STD* and logfile, to easily switch between them when changing fg/bg.
* src/log.h: Make redirect_output function externally linked.
* src/main.c: Don't use deprecated log_request_redirect_output function. Use redirect_output instead.
* src/mswindows.c: Don't use deprecated log_request_redirect_output function. Use redirect_output instead.
2016-10-21 19:33:29 +02:00
losgrandes
78e0ec5f03 Fixes #46584: wget --spider always returns zero exit status
* src/ftp.c: Return error as exit value if even one file doesn't exist
2016-10-21 10:24:28 +02:00
Tim Rühsen
807d1c7d94 * src/http.c (gethttp): Accept 206 for request w/o Range header
Fixes: #49319
2016-10-12 14:59:36 +02:00
Tim Rühsen
3d1d5b317b * tests/Makefile.am: Let WGETRC work on *nix and Windows 2016-10-07 13:27:07 +02:00
Tim Rühsen
517d799b6f Properly include iconv.h
* src/iri.c: Check HAVE_ICONV to include iconv.h
* src/url.c: Same
2016-10-07 13:24:15 +02:00
Tim Rühsen
f79bb20f1b * bootstrap.conf: Add pipe-posix for pipe() 2016-10-07 13:23:27 +02:00
Tim Rühsen
e5164a8260 Amend redirection behavior
* src/recur.c (descend_redirect): Ignore WG_RR_LIST and WG_RR_REGEX
  for redirections.
* testenv/Makefile.am: Add Test-recursive-redirect.py
* testenv/Test-recursive-redirect.py: New test

Test-recursive-redirect.py written by Dale R. Worley.

Reported-by: "Dale R. Worley" <worley@ariadne.com>
2016-10-07 11:49:07 +02:00
Matthew White
a35f3dd4f6 New: Metalink/XML v3 python class, update tests to use this class
* testenv/misc/metalinkv3_xml.py: New Metalink/XML v3 python class
* testenv/Test-metalink-xml-abspath-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-abspath.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-absprefix-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-absprefix.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-continue.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-emptyprefix-trust.py: Update test to use
  the new Metalink/XML v3 python class
* testenv/Test-metalink-xml-homepath-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-homepath.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-homeprefix-trust.py: Update test to use
  the new Metalink/XML v3 python class
* testenv/Test-metalink-xml-homeprefix.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-nohash.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-nourls.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-prefix-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-prefix.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-relpath-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-relpath.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-relprefix-trust.py: Update test to use the
  new Metalink/XML v3 python class
* testenv/Test-metalink-xml-relprefix.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-size.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml-trust.py: Update test to use the new
  Metalink/XML v3 python class
* testenv/Test-metalink-xml.py: Update test to use the new
  Metalink/XML v3 python class
2016-09-30 19:44:06 +02:00
Matthew White
c403e67935 New: --metalink-over-http Content-Type/Disposition Metalink/XML processing
* src/http.c (metalink_from_http): Process the Content-Type header.
  Add an application/metalink4+xml URL as metalink metaurl.  If the
  option opt.content_disposition is true, the Content-Disposition's
  filename is the metaurl's name
* doc/wget.texi: Update --content-disposition and --metalink-over-http
* doc/metalink-standard.txt: Update doc. Content-Type/Disposition
  processing through --metalink-over-http. Update download naming
  system about --trust-server-names and --content-disposition
* testenv/Makefile.am: Add new files
* testenv/Test-metalink-http-xml-type.py: New file. Metalink/HTTP
  Content-Type/Disposition header automated Metalink/XML tests
* testenv/Test-metalink-http-xml-type-trust.py: New file. Metalink/HTTP
  Content-Type/Disposition header with --trust-server-names automated
  Metalink/XML tests
* testenv/Test-metalink-http-xml-type-content.py: New file. Metalink/HTTP
  Content-Type/Disposition header with --content-disposition automated
  Metalink/XML tests
* testenv/Test-metalink-http-xml-type-trust-content.py: New file.
  Metalink/HTTP Content-Type/Disposition header with --trust-server-names
  and --content-disposition automated Metalink/XML tests

Process the Content-Type header, identify an application/metalink4+xml
file.  The Content-Disposition could provide an alternate name through
the "filename" field for the metalink xml file.  Respectively, the cli
options --metalink-over-http and --content-disposition are required.

When Metalink/XML auto-processing, to use the Content-Disposition's
filename, the cli option --trust-server-names is also required.
2016-09-30 19:44:06 +02:00
Matthew White
3021466817 Bugfix: Set NULL variable due to --content-disposition to Metalink origin
* src/http.c (http_loop): Prevent SIGSEGV when hstat.local_file is
  NULL, opt.content_disposition has a role in leaving the value unset
* src/http.c (gethttp): If hs->local_file is NULL (aka http_loop()'s
  hstat.local_file), set it to the value of hs->metalink->origin
2016-09-30 19:44:06 +02:00
Matthew White
c89767d8d1 New: --trust-server-names saves Metalink/HTTP xml files using the "name" field
* src/metalink.c (retrieve_from_metalink): If opt.trustservernames is
  true, use the basename of the metaurl's name to save the xml file
* doc/metalink-standard.txt: Update doc. With --trust-server-names any
  Metalink/HTTP Link application/metalink4+xml file is saved using the
  basename of the "name" field, if any. Update Metalink/HTTP examples
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-http-xml-trust-name.py: New file. Metalink/HTTP
  automated Metalink/XML, save xml files using the "name" field tests
2016-09-30 19:44:06 +02:00
Matthew White
f030cdf8e2 Bugfix: Detect when a metalink:file doesn't have any hash
* src/metalink.c (retrieve_from_metalink): Reject any metalink:file
  without hashes. Prompt the error and switch to the next file
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-nohash.py: New file. Metalink/XML with no
  hashes tests

Prevent SIGSEGV.
2016-09-30 19:44:06 +02:00
Matthew White
5dccb2a9ce Bugfix: Detect malformed base64 Metalink/HTTP Digest header
* src/http.c (metalink_from_http): Fix hash_bin_len type. Use ssize_t
  instead than size_t. Reject -1 as base64_decode() return value
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-http-baddigest.py: New file. Metalink/HTTP
  malformed base64 Digest header tests

On malformed base64 input, ssize_t base64_decode() returns -1. Such
value is too big for a size_t variable, and used as xmalloc() value
will exaust all the memory.
2016-09-30 19:44:06 +02:00
Matthew White
0538e791fb New option --metalink-index to process Metalink application/metalink4+xml
* NEWS: Mention the effect of --metalink-index over Metalink
* src/init.c: Add new option metalinkindex (opt.metalink_index),
  initialize to -1
* src/main.c: Add new option metalink-index (--metalink-index=NUMBER)
* src/options.h: Add new option metalink_index (int)
* src/metalink.h: Add declaration of functions fetch_metalink_file(),
  replace_metalink_basename()
* src/metalink.c: Add functions fetch_metalink_file() simple file
  fetch, replace_metalink_basename() replace file basename
* src/metalink.c (retrieve_from_metalink): New. Process Metalink
  application/metalink4+xml of opt.metalink_index ordinal number
* doc/wget.texi: Add new option metalink-index (--metalink-index)
  documentation
* doc/metalink-standard.txt: Updated doc. Add documentation about
  Metalink application/metalink4+xml metaurls download naming system
* doc/metalink-standard.txt: Update Metalink/XML and HTTP examples
* testenv/Makefile.am: Add new files
* testenv/Test-metalink-http-xml.py: New file. Metalink/HTTP automated
  Metalink/XML "application/metalink4+xml" --metalink-index tests
* testenv/Test-metalink-http-xml-trust.py: New file. Metalink/HTTP
  automated Metalink/XML "application/metalink4+xml" --metalink-index
  retrieval with --trust-server-names tests

WARNING: Do not use lib/dirname.c (dir_name) to get the directory
name, it may append a dot '.' character to the directory name.
2016-09-30 19:44:06 +02:00
Matthew White
acb1d1a668 Bugfix: Prevent sorting when there are less than two elements
* src/utils.c (stable_sort): Add condition nmemb > 1, sort only when
  there is more than one element

Prevent SIGSEGV.
2016-09-30 19:44:06 +02:00
Matthew White
628fb565c7 New: Parse Metalink/HTTP header for application/metalink4+xml
* src/http.c (metalink_from_http): Parse Metalink/HTTP header for
  metaurls application/metalink4+xml media types
* src/metalink.h: Add function declaration metalink_meta_cmp()
* src/metalink.c: Add function metalink_meta_cmp() compare metalink
  metaurls priorities

Add Metalink/HTTP application/metalink4+xml media types as metaurls to
the metalink variable that will be used to download the files.
2016-09-30 19:44:05 +02:00
Matthew White
64ab90ee66 New test: Metalink shall not concatenate '/' to an empty directory prefix
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-emptyprefix-trust.py: New file.
  Metalink/XML empty directory prefix (--directory-prefix '') tests

Detect a '/' character wrongfully concatenated to an empty directory
prefix '' (not NULL), resulting in an absolute path as '/dir/file',
instead than 'dir/file'.
2016-09-30 19:44:05 +02:00
Matthew White
9532861aef Bugfix: Remove surrounding quotes from Metalink/HTTP key's value
* src/metalink.h: Add declaration of function dequote_metalink_string()
* src/metalink.c: Add function dequote_metalink_string() remove
  surrounding quotes from string, \' or \"
* src/metalink.c (find_key_value, find_key_values): Call dequote_metalink_string()
  to remove the surrounding quotes from the parsed value
* src/metalink.c (test_find_key_value, test_find_key_values): Add
  quoted key's values for unit-tests
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-http-quoted.py: New file. Metalink/HTTP quoted
  values tests

Some Metalink/HTTP keys, like "type" [2], may have a quoted value [1]:
Link: <http://example.com/example.ext.meta4>; rel=describedby;
type="application/metalink4+xml"

Wget was expecting a dequoted value from the Metalink module. This
patch addresses this problem.

References:
 [1] Metalink/HTTP: Mirrors and Hashes
     1.1. Example Metalink Server Response
     https://tools.ietf.org/html/rfc6249#section-1.1

 [2] Additional Link Relations
     6. "type"
     https://tools.ietf.org/html/rfc6903#section-6
2016-09-30 19:44:05 +02:00
Matthew White
8aca8fc80d Bugfix: Process Metalink/XML url strings containing white spaces and CRLF
* src/metalink.h: Add declaration of function clean_metalink_string()
* src/metalink.c: Add directive #include "xmemdup0.h"
* src/metalink.c: Add function clean_metalink_string() remove leading
  and trailing white spaces and CRLF from string
* src/metalink.c (retrieve_from_metalink): Remove leading and trailing
  white spaces and CRLF from url resource mres->url
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-urlbreak.py: New test. Metalink/XML white
  spaces and CRLF in url resources tests

White spaces and CRLF are not automatically removed by libmetalink
from url strings. The Wget's Metalink module was unable to process
such url strings. This patch implements the processing of such url
strings cleaning off leading and trailing white spaces and CRLF.

If a parsed Metalink/XML url string contains strings separated by
CRLF, only the first of the series is accepted.
2016-09-30 19:44:05 +02:00
Matthew White
ba82a47173 New test: Detect when there are no good Metalink url resources
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-nourls.py: New file. Metalink/XML unknown
  urls tests

Test if when there are no good Metalink url resources there is any
segmentation fault.
2016-09-30 19:44:05 +02:00
Matthew White
70360b3eab New: Metalink file size mismatch returns error code METALINK_SIZE_ERROR
* src/wget.h (uerr_t): Add error code METALINK_SIZE_ERROR to enum
* src/metalink.c (retrieve_from_metalink): Use boolean variable
  size_ok, when false set retr_err to METALINK_SIZE_ERROR
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-size.py: New file. Metalink/XML file size
  tests (<size></size>)

Before this patch, no appropriate error code was returned to inform a
file size mismatch.

This patch introduces the error code METALINK_SIZE_ERROR to inform a
file size mismatch.
2016-09-30 19:44:05 +02:00
Matthew White
c29983a044 New: Metalink/XML and Metalink/HTTP file naming safety rules
* NEWS: Mention the effect of --trust-server-names over Metalink
* src/metalink.h: Add declaration of function append_suffix_number()
* src/metalink.c: Add function append_suffix_number() append number to
  string
* src/metalink.c (retrieve_from_metalink): Safer Metalink/XML and
  Metalink/HTTP download naming system, opt.trustservernames based
* doc/metalink-standard.txt: Update doc. Explain new Metalink/XML and
  Metalin/HTTP download naming system and --trust-server-names role
* testenv/Makefile.am: Add new files
* testenv/Test-metalink-xml-continue.py: Update test. Metalink/XML
  continue/keep existing files (HTTP 416) with --continue tests
* testenv/Test-metalink-xml.py: Update test. Metalink/XML naming tests
* testenv/Test-metalink-xml-trust.py: New file. Metalink/XML naming
  tests with --trust-server-names
* testenv/Test-metalink-xml-abspath.py: Update test. Metalink/XML
  absolute path tests
* testenv/Test-metalink-xml-abspath-trust.py: New file. Metalink/XML
  absolute path tests with --trust-server-names
* testenv/Test-metalink-xml-relpath.py: Update test. Metalink/XML
  relative path tests
* testenv/Test-metalink-xml-relpath-trust.py: New file. Metalink/XML
  relative path tests with --trust-server-names
* testenv/Test-metalink-xml-homepath.py: Update test. Metalink/XML
  home path and ~ (tilde) tests
* testenv/Test-metalink-xml-homepath-trust.py: New file. Metalink/XML
  home path and ~ (tilde) tests with --trust-server-names
* testenv/Test-metalink-xml-prefix.py: New file. Metalink/XML naming
  tests with --directory-prefix
* testenv/Test-metalink-xml-prefix-trust.py: New file. Metalink/XML
  naming tests with --directory-prefix and --trust-server-names
* testenv/Test-metalink-xml-absprefix.py: New file. Metalink/XML
  absolute --directory-prefix tests
* testenv/Test-metalink-xml-absprefix-trust.py: New file. Metalink/XML
  absolute --directory-prefix tests with --trust-server-names
* testenv/Test-metalink-xml-relprefix.py: New file. Metalink/XML
  relative --directory-prefix tests
* testenv/Test-metalink-xml-relprefix-trust.py: New file. Metalink/XML
  relative --directory-prefix tests with --trust-server-names
* testenv/Test-metalink-xml-homeprefix.py: New file. Metalink/XML home
  --directory-prefix tests
* testenv/Test-metalink-xml-homeprefix-trust.py: New file. Metalink/XML
  home --directory-prefix tests with --trust-server-names

The option --trust-server-names allows to use the file names parsed
from a Metalink/XML file.  Without --trust-server-names, the safety
mechanism provides secure and predictable file names.
2016-09-30 19:44:05 +02:00
Matthew White
5f3ed5eec8 New document: Metalink/XML and Metalink/HTTP standard reference
* doc/metalink-standard.txt: New doc. Implemented and recommended
  Metalink/XML and Metalink/HTTP standard features
2016-09-30 19:44:05 +02:00
Matthew White
43ec7008f2 Enforce Metalink file name verification, strip directory if necessary
* NEWS: Mention the use of a safe Metalink destination path
* src/metalink.h: Add declaration of functions get_metalink_basename(),
  last_component(), metalink_check_safe_path()
* src/metalink.c: Add directive #include "dosname.h"
* src/metalink.c: Add function get_metalink_basename() to return the
  basename of a file name, strip w32's drive letter prefixes
* src/metalink.c (retrieve_from_metalink): Enforce Metalink file name
  verification, if the file name is unsafe try its basename
* doc/metalink.txt: Update document. Explain --directory-prefix

The function get_metalink_basename() uses FILE_SYSTEM_PREFIX_LEN to
catch any 'C:D:file' (w32 environment), then it removes each drive
letter prefix, i.e. 'C:' and 'D:'.

Unsafe file names contain an absolute, relative, or home path.  Safe
paths can be verified by libmetalink's metalink_check_safe_path().
2016-09-30 19:44:03 +02:00
Matthew White
7d4942864b Implement Metalink/XML --directory-prefix option in Metalink module
* NEWS: Mention the effect of --directory-prefix over Metalink
* src/metalink.c (retrieve_from_metalink): Add opt.dir_prefix as
  prefix to the metalink:file name mfile->name
* doc/metalink.txt: Update document. Explain --directory-prefix

When --directory-prefix=<prefix> is used, set the top of the retrieval
tree to prefix. The default is . (the current directory). Metalink/XML
and Metalink/HTTP files will be downloaded under prefix.
2016-09-27 20:29:03 +02:00
Matthew White
666b7862bf Change mfile->name to filename in Metalink module's messages
* src/metalink.c (retrieve_from_metalink): Change mfile->name to
  filename when referring to the downloaded file

The file name could have been changed by unique_create() (or by any
other mean) before downloading. Use the name of the downloaded file
(filename) when printing output which refer to it.
2016-09-27 20:29:03 +02:00
Matthew White
f3f349a0cf Add file size computation in Metalink module
* NEWS: Mention Metalink's file size verification
* src/metalink.c (retrieve_from_metalink): Add file size computation
* doc/metalink.txt: Update document. Remove resolved bugs

Reject downloaded files when they do not agree with their Metalink/XML
metalink:size: https://tools.ietf.org/html/rfc5854#section-4.2.14

At the moment of writing, Metalink/HTTP headers do not provide a file
size field. This information could be obtained from the Content-Length
header field: https://tools.ietf.org/html/rfc6249#section-7
2016-09-27 20:29:03 +02:00
Matthew White
6b1860da37 Update Metalink/XML tests and add a new test for home paths
* testenv/Test-metalink-xml-relpath.py: Update test
* testenv/Test-metalink-xml-homepath.py: New file. Reject home paths
* testenv/Makefile.am: Add new file

When --input-metalink=<file> is used, each metalink:file name is
verified by libmetalink's metalink_check_safe_path(). By design,
absolute, relative and home paths are rejected.

At the moment of writing, when --metalink-over-http is used, absolute,
relative, and home paths aren't a concern. The destination file name
is a combination of URL's file name and cli's "Directory Options"
handled by src/url.c (url_file_name).
2016-09-27 20:29:03 +02:00
Matthew White
ff444ebc2a Bugfix: Keep the download progress when alternating metalink:url
* NEWS: Mention the effects of --continue over Metalink
* src/metalink.c (retrieve_from_metalink): On download error, resume
  output_stream with the next mres->url. Keep fully downloaded files
  started with --continue, otherwise rename/remove the file
* testenv/Makefile.am: Add new file
* testenv/Test-metalink-xml-continue.py: New file. Metalink/XML
  continue/keep existing files (HTTP 416) with --continue tests

Before this patch, with --continue, existing and/or fully retrieved
files which fail the sanity tests were renamed (--keep-badhash), or
removed.

This patch ensures that --continue doesn't rename/remove existing
and/or fully retrieved files (HTTP 416) which fail the sanity tests.
2016-09-27 20:28:50 +02:00
Matthew White
96554861f9 Bugfix: Fix NULL filename and output_stream in Metalink module
* NEWS: Mention the Metalink "path/file" name format handling
* src/metalink.c (retrieve_from_metalink): Fix NULL filename, set
  filename to the right "path/file" value
* src/metalink.c (retrieve_from_metalink): Fix NULL output_stream, set
  output_stream to filename when it is created by retrieve_url()
* src/metalink.c (retrieve_from_metalink): Add RFC5854 comments about
  proper metalink:file "path/file" name format handling
* doc/metalink.txt: Update document. Remove resolved bugs

If unique_create() cannot create/open the destination file, filename
and output_stream remain NULL. If fopen() is used instead, filename
always remains NULL. Both functions cannot create "path/file" trees.

Setting filename to the right value is sufficient to prevent SIGSEGV
generating from testing a NULL value. This also allows retrieve_url()
to create a "path/file" tree through opt.output_document.

Reading NULL as output_stream, when it shall not be, leads to wrong
results. For instance, a non-NULL output_stream tells when a stream
was interrupted, reading NULL instead means to assume the contrary.

This patch conforms to the RFC5854 specification:
  The Metalink Download Description Format
  4.1.2.1.  The "name" Attribute
  https://tools.ietf.org/html/rfc5854#section-4.1.2.1
2016-09-27 20:17:08 +02:00
Matthew White
bcb9bf7ae4 Add metalink description
* doc/metalink.txt

Evaluation of "Directory Options" on the command line interacting with
the option '--input-metalink=file':

$ wget --input-metalink=file <directory options>
2016-09-19 05:56:40 +02:00
Matthew White
ea038006d1 Use python .replace instead than re.sub in Metalink tests
* testenv/Test-metalink-http.py: Use python .replace
* testenv/Test-metalink-xml.py: Use python .replace
* testenv/Test-metalink-xml-abspath.py: Use python .replace
* testenv/Test-metalink-xml-relpath.py: Use python .replace

Use python .replace instead than re.sub, remove 'import re'.
2016-09-19 05:56:40 +02:00
Matthew White
77e2c54991 Fix: Change Metalink/XML v3 file name into test.metalink
* testenv/Test-metalink-xml-abspath.py: Change Metalink/XML v3 file
  name from test.meta4 into test.metalink
* testenv/Test-metalink-xml-relpath.py: Change Metalink/XML v3 file
  name from test.meta4 into test.metalink
* testenv/Test-metalink-xml.py: Change Metalink/XML v3 file name from
  test.meta4 into test.metalink
2016-09-19 05:55:04 +02:00
Tim Rühsen
7ffbccec4c Add two Metalink/XML tests
* testenv/Test-metalink-xml-abspath.py: Reject absolute paths
* testenv/Test-metalink-xml-relpath.py: Reject relative paths
* testenv/Makefile.am: Add both new files to metalink tests
2016-09-13 11:45:02 +02:00
Tim Rühsen
a2c4849900 Fix crash on 'srcset' inline URIs
* src/html-url.c (tag_handle_img): Check append_url() for NULL
  return value before dereference.

Crashed reproducable with parsing srcset="data:..." inline data.
Reported-by: Coverity
2016-09-09 11:44:02 +02:00
Tim Rühsen
40870e1271 * src/hsts.c (hsts_store_open): NULL check param for fclose().
Reported-by: Coverity
2016-09-09 10:22:58 +02:00
Tim Rühsen
15c1e0eb7b * src/ftp-ls.c (ftp_parse_winnt_ls): Fix memset params 2016-09-09 10:22:58 +02:00
Tim Rühsen
eba724a128 * src/utils.c (stable_sort): Use xmalloc instead of malloc 2016-09-09 10:22:58 +02:00
Tim Rühsen
66a9883c8f * src/ftp-ls.c (ftp_parse_winnt_ls): Initialize struct fileinfo cur
Reported-by: Coverity
2016-09-08 16:51:15 +02:00
Tim Rühsen
4febe72bd2 Add const to url param of some functions
* src/http.c: Add const to first param of initialize_request(),
  initialize_proxy_configuration(), establish_connection(),
  check_file_output(), check_auth(), gethttp(), http_loop().
* src/http.h: Add const to first param of http_loop().
2016-09-08 16:13:54 +02:00
Tim Rühsen
c629ec7fd1 * Makefile.am: Remove trailing empty line 2016-09-08 14:20:33 +02:00
Tim Rühsen
03da900c5b * src/recur.c (retrieve_tree): Fix possible NULL dereference
Reported-by: Coverity
2016-09-08 13:04:37 +02:00
Tim Rühsen
b7b67e23cd * src/http.c (initialize_request): Fix check for user
Reported-by: Coverity
2016-09-08 12:48:32 +02:00
Tim Rühsen
22aed3ed4b * src/retr.c (retrieve_url): NULL check mynewloc
Reported-by: Coverity
2016-09-08 12:46:25 +02:00
Tim Rühsen
b4465afa8a * src/utils.c (stable_sort): Reduce tmp allocation size
Reported-by: Coverity
2016-09-08 12:44:17 +02:00
Tim Rühsen
a232835fd1 * Makefile.am: Add target 'check-valgrind' 2016-09-08 11:20:25 +02:00
Tim Rühsen
a78b83b1e9 Fix some issues detected by Coverity
* src/connect.c (connect_to_ip): Check return value of setsockopt.
* src/ftp.c (ftp_retrieve_list): Check return value of chmod.
* src/http.c (digest_authentication_encode): Cleanup code.
* src/init.c (setval_internal): Explicitely check comind range.
* src/main.c (main): Explicitely check optarg.
* src/retr.c (retr_rate): Use snprintf instead sprintf,
  (retrieve_from_file): More verbose error message,
  (rotate_backups): Use snprintf instead sprintf, check return
  value of rename().
* src/url.c (mkalldirs): Check return value of unlink().
* src/utils.c (strdupdelim): Explicitely check beg and end for NULL,
  (merge_vecs): Fix sizeof argument to char *,
  (stable_sort): Use malloc instead of alloca.
2016-09-08 10:12:02 +02:00
Tim Rühsen
37a5257c66 Code cleanup for --use-askpass
* bootstrap.conf: Add xmemdup0 and strpbrk.
* src/init.c (cmd_use_askpass): Add 'const' to char *,
  remove check for file existence.
* src/main.c (run_use_askpass): C89 compat init of argv,
  added \n to error messages,
  fixed stripping of \n and \r from input,
  make run_use_askpass and use_askpass static.
2016-09-08 09:07:32 +02:00
Tim Rühsen
49af22ca94 * src/http.c (check_file_output): Replace asprintf by aprint 2016-09-07 09:31:43 +02:00
Tim Rühsen
d505714a32 * testenv/README: Remove obsolete references to TEST_NAME 2016-09-04 14:56:06 +02:00
Liam R. Howlett
21e1725e12 Add --use-askpass=COMMAND support
* doc/wget.texi: Add --use-askpass to documentation.
* src/init.c: Add cmd_use_askpasss to set opt.use_askpass based on
argument, WGET_ASKPASS, and SSH_ASKPASS environment variables.
opt.wget-askpass is freed in cleanup ()
* src/main.c: Update options & add spawn process of opt.use_askpass
command.
* src/options.h: Addition of string use_askpass.
* src/url.c: Function scheme_leading_string to access the leading
string of a parsed url.
* src/url.h: Prototype for scheme_leading_string for returning the
leading string.
* bootstrap.conf: Add posix_spawn to gnulib_modules

This adds the --use-askpass option which is disabled by default.

--use-askpass=COMMAND will request the username and password for a given
URL by executing the external program COMMAND.  If COMMAND is left
blank, then the external program in the environment variable
WGET_ASKPASS will be used.  If WGET_ASKPASS is not set then the
environment variable SSH_ASKPASS is used.  If there is no value set, an
error is returned.  If an error occurs requesting the username or
password, wget will exit.

Signed-off-by: Liam R. Howlett <Liam.Howlett@WindRiver.com>
2016-09-03 21:01:24 +02:00
Dale R. Worley
796e30dcea Add tests for recursion and redirection.
* testenv/Test-recursive-basic.py: New file. Test basic recursion
    * testenv/Test-recursive-include.py: New File. Recursion test with
    include directories
    * testenv/Test-redirect.py: New File. Basic redirection tests
    * testenv/Makefile.am: Add new tests to makefile
2016-09-02 17:46:36 +02:00
Dale R. Worley
b919f988f2 Sort test names into order.
* testenv/Makefile.am: Sort all the python tests in alphabetical
    order
2016-09-02 17:45:19 +02:00
Dale R. Worley
ca1ee7d32f Corrections and amplifications to test documentation
* testenv/README: Update documentation to meet current project
    status
    * testenv/Test-Proto.py: Same
2016-09-02 17:44:10 +02:00
Giuseppe Scrivano
690c47e3b1 Append .tmp to temporary files
* src/http.c (struct http_stat): Add `temporary` flag.
(check_file_output): Append .tmp to temporary files.
(open_output_stream): Refactor condition to use hs->temporary instead.

Reported-by: "Misra, Deapesh" <dmisra@verisign.com>
Discovered by: Dawid Golunski (http://legalhackers.com)
2016-08-24 12:29:01 +02:00
Tim Rühsen
9ffb64ba6a Limit file mode to u=rw on temp. downloaded files
* bootstrap.conf: Add gnulib modules fopen, open.
* src/http.c (open_output_stream): Limit file mode to u=rw
on temporary downloaded files.

Reported-by: "Misra, Deapesh" <dmisra@verisign.com>
Discovered by: Dawid Golunski (http://legalhackers.com)
2016-08-24 12:28:55 +02:00
Giuseppe Scrivano
6698260f15 Fix some make syntax-check issues
cfg.mk: Skip .der files.
testenv/certs/server-template.cfg: Remove empty final line.
testenv/certs/ca-template.cfg: Likewise.
2016-08-21 15:35:36 +02:00
Tim Rühsen
0787d7253e * src/css-url.c (get_urls_css): Fix memory leak 2016-08-17 23:13:27 +02:00
Tim Rühsen
964f4646da * src/html-url.c (get_urls_html): Fix memory leak 2016-08-17 23:12:25 +02:00
Tim Rühsen
262baeb113 Improve PSL cookie checking
* configure.ac: Add --with-psl-file to set a PSL file
* src/cookies.c (check_domain_match): Load PSL_FILE with
  fallback to built-in data.

This change allows package maintainers to make Wget use the latest
PSL (DAFSA or plain text), without updating libpsl itself.

E.g. Debian now comes with a DAFSA binary within the 'publicsuffix'
package which allows very fast loading (no parsing or processing needed).
2016-08-17 16:32:26 +02:00
Tobias Stoeckmann
f4aeb41899 Fix stack overflow with way too many cookies
* src/cookies.c (cookie_header): Use heap instead of stack.
* src/http.c (request_send): Likewise.

If wget has to handle an insanely large amount of cookies (~700,000 on
32 bit systems or ~530,000 on 64 bit systems), the stack is not large
enough to hold these pointers, leading to undefined behaviour according
to POSIX; expect a segmentation fault in real life. ;)

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2016-08-10 19:59:25 +02:00
Tobias Stoeckmann
a9d49e5b15 Fix signal race condition
The signal handler for SIGALRM calls longjmp, but the handler is
installed before the jump target has been initialized. If another
process sends SIGALRM right between handler installation and target
initialization, the jump leads to undefined behavior.

This can easily be fixed by moving the signal handler installation
into the "SETJMP == 0" conditional block, which means that the target
has just been initialized.

* src/utils.c: call signal after SETJMP.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2016-08-09 17:38:29 +02:00
Jeffery To
0fe79eeacb Remove hyphens from command names
* src/init.c: Remove hyphens from command names
* src/main.c: Likewise

Options with hyphens (or underscores) in their command name cannot be
set in a wgetrc file.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
2016-08-05 09:45:09 +02:00
Tim Rühsen
e3fb4c3859 * src/metalink.c (badhash_suffix): Fix quoting 2016-08-04 13:09:28 +02:00
Matthew White
943a6d585f Add new option --keep-badhash to keep Metalink's files with a bad hash
* src/init.c: Add keepbadhash
* src/main.c: Add keep-badhash
* src/options.h: Add keep_badhash
* doc/wget.texi: Add docs for --keep-badhash
* src/metalink.h: Add prototypes badhash_suffix(), badhash_or_remove()
* src/metalink.c: New functions badhash_suffix(), badhash_or_remove().
  (retrieve_from_metalink): Call badhash_or_remove() on download error

With --keep-badhash, append .badhash to Metalink's files with checksum
mismatch. (retrieve_from_metalink): unique_create() may append another
suffix to avoid overwriting existing files.

Without --keep-badhash, remove downloaded files with checksum mismatch
(this conforms to the old behaviour).
2016-08-04 12:03:49 +02:00
Tim Rühsen
7fad76db4c * src/metalink.c: Remove C++ style comments 2016-08-03 13:48:07 +02:00
Matthew White
3e7e29f358 Add gnulib modules 'link', 'unlink' and 'symlink'
* bootstrap.conf: Add 'link', 'unlink' and 'symlink'
2016-08-03 13:44:34 +02:00
Matthew White
e0b60fd073 New: --continue continues partially downloaded Metalink's files
* src/metalink.c (retrieve_from_metalink): Continue file download if
  opt.always_rest is true

Without --continue, download as a new file with an unique name (this
conforms to the old behaviour).
2016-08-03 13:37:27 +02:00
Matthew White
9db02a0c46 Add support for Metalink's md2, and md4 hashes
* bootstrap.conf: Add crypto/md2, and crypto/md4
* src/metalink.c (retrieve_from_metalink): Add md2, and md4 support

This patch adds support for the deprecated (insecure) md2, and md4
Message-Digest algorithms to the Metalink module.
2016-08-03 12:58:43 +02:00
Matthew White
edad3c1df3 Add support for Metalink's md5, sha1, sha224, sha384, and sha512 hashes
* bootstrap.conf: Add crypto/sha512
* src/metalink.c (retrieve_from_metalink): Add md5, sha1, sha224,
  sha384, and sha512 support

Metalink's checksum verification was limited to sha256. This patch
adds support for md5, sha1, sha224, sha384, and sha512.
2016-08-03 12:49:26 +02:00
Sean Burford
20cac2c5ab Style fixes and DEBUG on setxattr failure.
* src/ftp.c: Fix style.
* src/http.c: Likewise.
* src/xattr.h: Likewise.
* src/xattr.c: Likewise,
  (write_xattr_metadata): Print debug msg on error.
2016-07-27 17:05:57 +02:00
Sean Burford
a933bdd31e Keep fetched URLs in POSIX extended attributes
* configure.ac: Check for xattr availability
* src/Makefile.am: Add xattr.c
* src/ftp.c: Include xattr.h.
  (getftp): Set attributes if enabled.
* src/http.c: Include xattr.h.
  (gethttp): Add parameter 'original_url',
  set attributes if enabled.
  (http_loop): Add 'original_url' to call of gethttp().
* src/init.c: Add new option --xattr.
* src/main.c: Add new option --xattr, add description to help text.
* src/options.h: Add new config member 'enable_xattr'.
* src/xatrr.c: New file.
* src/xattr.h: New file.

These attributes provide a lightweight method of later determining
where a file was downloaded from.

This patch changes:
*   autoconf detects whether extended attributes are available and
    enables the code if they are.
*   The new flags --xattr and --no-xattr control whether xattr is enabled.
*   The new command "xattr = (on|off)" can be used in ~/.wgetrc or /etc/wgetrc
*   The original and redirected URLs are recorded as shown below.
*   This works for both single fetches and recursive mode.

The attributes that are set are:
user.xdg.origin.url: The URL that the content was fetched from.
user.xdg.referrer.url: The URL that was originally requested.

Here is an example, where http://archive.org redirects to https://archive.org:
$ wget --xattr http://archive.org
...
$ getfattr -d index.html
user.xdg.origin.url="https://archive.org/"
user.xdg.referrer.url="http://archive.org/"

These attributes were chosen based on those stored by Google Chrome
https://bugs.chromium.org/p/chromium/issues/detail?id=45903
and curl https://github.com/curl/curl/blob/master/src/tool_xattr.c
2016-07-22 13:42:23 +02:00
Noël Köthe
ef372a4f27 Fix typos
* ChangeLog-2014-12-10: invokation -> invocation
* doc/wget.texi: invokation -> invocation
* src/main.c: seperated -> separated
* src/options.h: seperated -> separated
* testenv/README: invokation -> invocation
* testenv/conf/wget_commands.py: invokation -> invocation
2016-07-02 19:01:24 +02:00
Tim Rühsen
0b151f51eb Fix creating docs when make uses 'sh -e'
* doc/Makefile.am: Save fallback for pod2man --utf8

Reported-by: Jérémie Courrèges-Anglas <jca@wxcvbn.org>
2016-06-30 15:19:26 +02:00
Tim Rühsen
309e72c74f Fix compilation for OpenSSL 1.1.0
* src/openssl.c (ssl_init): Use SSL_is_init_finished() instead of
  SSL_state(), conditionally skip SSLeay function calls

The python test suite makes SSL_peek() hang, consuming 100% CPU time.
This does not happen on real world TLS connections, though, but needs
investigations.
2016-06-30 13:24:33 +02:00
Tim Rühsen
2318c309d4 Add script to generate test certs non-interactive
* Test-pinnedpubkey-hash-https.py: Read hashed pubkey from file
* Test-pinnedpubkey-hash-no-check-fail-https.py: Use invalid hash
* certs/make_ca.sh: New script to generate test certs non-interactive
* certs/ca-template.cfg: New file (template for CA cert)
* certs/server-template.cfg: New file (template for server cert)
* certs/server-pubkey-sha256.base64: New file (pubkey sha256 hash)
2016-06-29 12:54:06 +02:00
Ander Juaristi
cdc3e28d8e Bypass world-writable checks on Windows
* src/hsts.c (hsts_file_access_valid): we should check for "world-writable"
   files only on Unix-based systems. It's difficult to mimic the same behavior
   on Windows, so it's better to just not do it.

Reported-by: Gisle Vanem <gvanem@yahoo.no>
Reported-by: Eli Zaretskii <eliz@gnu.org>
2016-06-27 09:54:32 +02:00
Tim Rühsen
43359f47c4 Update gnulib and bootstrap
* gnulib: Sync gnulib submodule with upstream
* bootstrap: Update to latest version from gnulib/build-aux/
2016-06-14 09:27:58 +02:00
Tim Rühsen
e1e7afb210 Use ICONV_CONST to avoid type warning for iconv()
* src/iri.c (do_conversion): Cast 2. param of iconv() to
 'ICONV_CONST char **'
* src/url.c (convert_fname): Likewise
2016-06-12 21:51:34 +02:00
Tim Rühsen
7e585fe23d Remove check for HAVE_ICONV in src/url.c
* src/url.c: Remove check for HAVE_ICONV
2016-06-12 21:49:23 +02:00
Tim Rühsen
526e98f7c4 Add gnulib module 'langinfo'
* bootstrap.conf: Add 'langinfo'
2016-06-12 20:55:03 +02:00
Tim Rühsen
d75f43f083 Include gnulib fcntl.h instead of sys/fcntl.h
* src/gnutls.c: Include gnulib fcntl.h
2016-06-12 17:06:31 +02:00
Tim Rühsen
d4f97dc9af Add libraries to LDADD for wget
* src/Makefile.am: Add $(GETADDRINFO_LIB) $(HOSTENT_LIB) $(INET_NTOP_LIB)
 $(LIBSOCKET) $(LIB_CLOCK_GETTIME) $(LIB_CRYPTO) $(LIB_SELECT)
 $(LTLIBICONV) $(LTLIBINTL) $(LTLIBTHREAD) $(SERVENT_LIB) to LDADD
2016-06-12 17:02:12 +02:00
Tim Rühsen
ade62eb400 Explicitely mention Python3 in README.checkout
* README.checkout: Python test suite needs Python3
2016-06-10 15:14:43 +02:00
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
159 changed files with 10314 additions and 2394 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
- libidn2-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

@@ -729,7 +729,7 @@
* testenv/Makefile.am: Run the tests in Python's Optimizedmode
* testenv/conf/__init__.py (gen_hook): Use try..except instead of if..else
* testenv/misc/color_terminal.py: System and check will not change while a test is
run. Do not test for them on every invokation of printer()
run. Do not test for them on every invocation of printer()
* testenv/server/http/http_server.py: The ssl and re modules are required by
specific functions. Load them lazily
(HTTPSServer.__init__): Lazy load ssl module here

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

View File

@@ -77,3 +77,6 @@ gen-ChangeLog:
{ rm -f $(distdir)/ChangeLog && \
mv $(distdir)/cl-t $(distdir)/ChangeLog; } \
fi
check-valgrind:
TESTS_ENVIRONMENT="VALGRIND_TESTS=1" $(MAKE) check

87
NEWS
View File

@@ -1,12 +1,93 @@
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, 2015 Free
Software Foundation, Inc.
Copyright (C) 1997-2017 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.19
* New option --use-askpass=COMMAND. Fetch user/password by calling
an external program.
* Use IDNA2008 (+ TR46 if available) through libidn2
* When processing a Metalink header, --metalink-index=<number> allows
to process the header's application/metalink4+xml files.
* When processing a Metalink file, --trust-server-names enables the
use of the destination file names specified in the Metalink file,
otherwise a safe destination file name is computed.
* When processing a Metalink file, enforce a safe destination path.
Remove any drive letter prefix under w32, i.e. 'C:D:file'. Call
libmetalink's metalink_check_safe_path() to prevent absolute,
relative, or home paths:
https://tools.ietf.org/html/rfc5854#section-4.1.2.1
https://tools.ietf.org/html/rfc5854#section-4.2.8.3
* When processing a Metalink file, --directory-prefix=<prefix> sets
the top of the retrieval tree to prefix for Metalink downloads.
* When processing a Metalink file, reject downloaded files which don't
agree with their own metalink:size value:
https://tools.ietf.org/html/rfc5854#section-4.2.16
* When processing a Metalink file, with --continue resume partially
downloaded files and keep fully downloaded files even if they fail
the verification.
* When processing a Metalink file, create the parent directories of a
"path/file" destination file name:
https://tools.ietf.org/html/rfc5854#section-4.1.2.1
https://tools.ietf.org/html/rfc5854#section-4.2.8.3
* On a recursive download, append a .tmp suffix to temporary files
that will be deleted after being parsed, and create them
readable/writable only by the owner.
* New make target 'check-valgrind'
* Fix several bugs
* Fix compatibility issues
* 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.

View File

@@ -4,7 +4,7 @@ Compiling From Repository Sources
does not contain automatically-generated files, even when these are
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,
more of the following (note that gettext, OpenSSL, GnuTLS, libidn2,
libiconv, libpsl, libpcre, pkg-config, libmetalink and GnuPG are not
absolutely required):
@@ -25,14 +25,15 @@ Compiling From Repository Sources
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 and python (see below). To execute all the tests
you need [24]libwww-perl and libio-socket-ssl-perl perl library. If
"perl -MCPAN -e 'install Bundle::LWP'" fails then you most likely don't
have cpan module installed. First download [25]CPAN and [26]install it.
Then execute "perl -MCPAN -e 'install Bundle::LWP'".
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
* [45]Python3, 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 Python3
tests. More information about the test suite below in the section
"Testing and development".
@@ -68,7 +69,7 @@ Compiling From Repository Sources
If you want to compile+link a non-system library version use
--with-libssl-prefix (or if having pkg-config: see description below).
* [31]libidn is required for IDN/IRI support (non-ASCII characters
* [31]libidn2 is required for IDN/IRI support (non-ASCII characters
within what would otherwise be URLs).
* [32]libiconv is required on non-GNU systems, for IDN/IRI support.
@@ -99,6 +100,9 @@ Compiling From Repository Sources
* [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
@@ -155,7 +159,7 @@ Testing and development
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>.
<https://www.gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
@@ -179,31 +183,32 @@ Testing and development
References
20. http://www.gnu.org/software/autoconf/
21. http://www.gnu.org/software/automake/
22. http://flex.sourceforge.net/
23. http://www.perl.org/
20. https://www.gnu.org/software/autoconf/
21. https://www.gnu.org/software/automake/
22. https://github.com/westes/flex
23. https://www.perl.org/
24. http://search.cpan.org/dist/libwww-perl/lib/Bundle/LWP.pm
25. http://search.cpan.org/CPAN/authors/id/A/AN/ANDK/CPAN-1.9402.tar.gz
26. http://apthorpe.cynistar.net/code/configuring_cpan.html
27. http://www.gnu.org/software/texinfo/
28. http://www.gnu.org/software/gettext/
29. http://www.gnu.org/software/gnutls/
30. http://www.openssl.org/
31. http://www.gnu.org/software/libidn/
32. http://www.gnu.org/software/libiconv/
33. http://git-scm.com/
27. https://www.gnu.org/software/texinfo/
28. https://www.gnu.org/software/gettext/
29. https://www.gnu.org/software/gnutls/
30. https://www.openssl.org/
31. https://www.gnu.org/software/libidn/#libidn2
32. https://www.gnu.org/software/libiconv/
33. https://git-scm.com/
34. https://github.com/rockdaboot/libpsl
35. http://www.pcre.org
36. http://wget.addictivecode.org/CompilingRepoSources?action=edit&editor=text
37. http://wget.addictivecode.org/CompilingRepoSources
38. http://wget.addictivecode.org/CompilingRepoSources?action=info
39. http://wget.addictivecode.org/CompilingRepoSources?action=AttachFile
40. http://moinmo.in/
41. http://moinmo.in/Python
42. http://moinmo.in/GPL
43. http://validator.w3.org/check?uri=referer
40. https://moinmo.in/
41. https://moinmo.in/Python
42. https://moinmo.in/GPL
43. https://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. https://c-ares.haxx.se/

View File

@@ -1,10 +1,10 @@
#! /bin/sh
# Print a version string.
scriptversion=2013-12-05.23; # UTC
scriptversion=2016-01-24.06; # UTC
# Bootstrap this package from checked-out sources.
# Copyright (C) 2003-2014 Free Software Foundation, Inc.
# Copyright (C) 2003-2016 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
@@ -42,6 +42,9 @@ export LC_ALL
local_gl_dir=gl
# Honor $PERL, but work even if there is none.
PERL="${PERL-perl}"
me=$0
usage() {
@@ -456,6 +459,7 @@ check_versions() {
test "$appvar" = TAR && appvar=AMTAR
case $appvar in
GZIP) ;; # Do not use $GZIP: it contains gzip options.
PERL::*) ;; # Keep perl modules as-is
*) eval "app=\${$appvar-$app}" ;;
esac
@@ -473,6 +477,17 @@ check_versions() {
ret=1
continue
} ;;
# Another check is for perl modules. These can be written as
# e.g. perl::XML::XPath in case of XML::XPath module, etc.
perl::*)
# Extract module name
app="${app#perl::}"
if ! $PERL -m"$app" -e 'exit 0' >/dev/null 2>&1; then
warn_ "Error: perl module '$app' not found"
ret=1
fi
continue
;;
esac
if [ "$req_ver" = "-" ]; then
# Merely require app to exist; not all prereq apps are well-behaved
@@ -900,7 +915,8 @@ if test $use_libtool = 1; then
esac
fi
echo "$0: $gnulib_tool $gnulib_tool_options --import ..."
$gnulib_tool $gnulib_tool_options --import $gnulib_modules &&
$gnulib_tool $gnulib_tool_options --import $gnulib_modules \
|| die "gnulib-tool failed"
for file in $gnulib_files; do
symlink_to_dir "$GNULIB_SRCDIR" $file \
@@ -1005,6 +1021,6 @@ echo "$0: done. Now you can run './configure'."
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -38,7 +38,9 @@ close
connect
dirname
fcntl
flock
fnmatch
fopen
futimens
ftello
getaddrinfo
@@ -51,9 +53,16 @@ gettext
gitlog-to-changelog
git-version-gen
gnupload
hostent
ioctl
iconv
iconv-h
inet_ntop
intprops
inttypes
langinfo
limits-h
link
listen
maintainer-makefile
mbiter
@@ -62,9 +71,16 @@ memrchr
mkdir
mkstemp
mkostemp
nanosleep
crypto/md2
crypto/md4
crypto/md5
crypto/sha1
crypto/sha256
crypto/sha512
open
pipe-posix
posix_spawn
quote
quotearg
recv
@@ -72,24 +88,36 @@ regex
select
send
setsockopt
signal-h
sigprocmask
sigpipe
snprintf
socket
spawn-pipe
stat
stdbool
stdint
strcase
strerror_r-posix
strpbrk
strptime
strtok_r
strtoll
symlink
sys_types
timegm
tmpdir
unlink
unlocked-io
update-copyright
libunistring-optional
unistr/base
unicase/tolower
utimens
vasprintf
vsnprintf
write
xmemdup0
xstrndup
"

2
cfg.mk
View File

@@ -26,4 +26,4 @@ local-checks-to-skip = \
show-vc-list-except:
@$(VC_LIST_EXCEPT)
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|((msdos|vms)/.*)|ChangeLog-2014-12-10$$
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|((msdos|vms)/.*)|ChangeLog-2014-12-10|/.*.der$$

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,7 +72,6 @@ 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 of zlib for compression
AC_ARG_WITH([zlib],
[AS_HELP_STRING([--without-zlib], [disable zlib.])])
@@ -79,6 +80,9 @@ 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
dnl
@@ -180,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
@@ -286,15 +290,6 @@ AC_DEFINE([HAVE_STRNCASECMP], 1, [Define to 1 if you have the `strncasecmp' func
AC_DEFINE([HAVE_STRDUP], 1, [Define to 1 if you have the `strdup' function.])
AC_DEFINE([HAVE_ISATTY], 1, [Define to 1 if you have the `isatty' function.])
dnl
dnl Call Wget-specific macros defined in aclocal.
dnl
WGET_STRUCT_UTIMBUF
WGET_FNMATCH
WGET_NANOSLEEP
WGET_POSIX_CLOCK
WGET_NSL_SOCKET
dnl Deal with specific hosts
case $host_os in
*mingw32* )
@@ -325,6 +320,10 @@ AS_IF([test "x$with_libpsl" != xno], [
])
])
AS_IF([test x"$with_libpsl" = xyes], [
AC_CHECK_FUNCS(psl_latest)
])
AS_IF([test x"$with_zlib" != xno], [
with_zlib=yes
PKG_CHECK_MODULES([ZLIB], zlib, [
@@ -631,9 +630,6 @@ AC_ARG_ENABLE(iri,
]
)
AC_ARG_WITH(libidn, AC_HELP_STRING([--with-libidn=[DIR]],
[Support IDN/IRIs (needs GNU Libidn)]),
libidn=$withval, libidn="")
AS_IF([test "X$iri" != "Xno"],[
AM_ICONV
@@ -651,33 +647,26 @@ AS_IF([test "X$iri" != "Xno"],[
LIBICONV=
])
AC_ARG_WITH(libidn, AC_HELP_STRING([--with-libidn=[DIR]],
[Support IDN2008/IRIs (needs GNU libidn2 + libunicode)]),
libidn=$withval, libidn="")
if test "X$iri" != "Xno"; then
if test "$libidn" != ""; then
LDFLAGS="${LDFLAGS} -L$libidn/lib"
CPPFLAGS="${CPPFLAGS} -I$libidn/include"
fi
AS_IF([test "x$with_libidn2" != xno], [
AC_SEARCH_LIBS(idn2_lookup_u8, idn2,
[with_libidn2=yes; AC_DEFINE([ENABLE_IRI], 1, [Define if IRI support is enabled.])],
[with_libidn2=no; iri=no; AC_MSG_WARN(*** LIBIDN2 was not found. You will not be able to use IDN2008 support)])
# If idna.h can't be found, check to see if it was installed under
# /usr/include/idn (OpenSolaris, at least, places it there).
# Check for idn-int.h in that case, because idna.h won't find
# idn-int.h until we've decided to add -I/usr/include/idn.
AC_CHECK_HEADER(idna.h, ,
[AC_CHECK_HEADER(idn/idn-int.h,
[CPPFLAGS="${CPPFLAGS} -I/usr/include/idn"],
[iri=no])]
)
if test "X$iri" != "Xno"; then
AC_CHECK_LIB(idn, stringprep_check_version,
[iri=yes LIBS="${LIBS} -lidn"], iri=no)
fi
if test "X$iri" != "Xno" ; then
AC_DEFINE([ENABLE_IRI], 1, [Define if IRI support is enabled.])
AC_MSG_NOTICE([Enabling support for IRI.])
else
AC_MSG_WARN([Libidn not found])
fi
# AS_IF([test "x$with_libidn2" = xyes], [
# AC_SEARCH_LIBS(u8_tolower, unistring,
# [AC_DEFINE([ENABLE_IRI], 1, [Define if IRI support is enabled.])],
# [iri=no; AC_MSG_WARN(*** LIBUNISTRING was not found. You will not be able to use IDN2008 support)])
# ])
])
fi
if test "X$iri" = "Xno"; then
# we don't need libunistring - clear settings from gnulib module
LIBUNISTRING=""
LTLIBUNISTRING=""
fi
dnl
@@ -742,11 +731,62 @@ 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
dnl Extended Attribute support
dnl
AC_ARG_ENABLE([xattr],
[AS_HELP_STRING([--disable-xattr], [disable support for POSIX Extended Attributes])],
[ENABLE_XATTR=$enableval],
[ENABLE_XATTR=yes])
case "$host_os" in
*linux* | *darwin*) xattr_syscalls="fsetxattr" ;;
freebsd*) xattr_syscalls="extattr_set_fd" ;;
*) AC_MSG_NOTICE([Disabling Extended Attribute support: your system is not known to support extended attributes.])
ENABLE_XATTR=no
esac
if test "X${ENABLE_XATTR}" = "Xyes"; then
AC_CHECK_FUNCS([$xattr_syscalls], [], [
AC_MSG_NOTICE([Disabling Extended Attribute support: your system does not support $xattr_syscalls])
ENABLE_XATTR=no
])
fi
test "X${ENABLE_XATTR}" = "Xyes" && AC_DEFINE([ENABLE_XATTR], 1,
[Define if you want file meta-data storing into POSIX Extended Attributes compiled in.])
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"])
AM_CONDITIONAL([WITH_XATTR], [test "X$ENABLE_XATTR" != "Xno"])
dnl
dnl Create output
@@ -772,9 +812,12 @@ AC_MSG_NOTICE([Summary of build options:
Digest: $ENABLE_DIGEST
NTLM: $ENABLE_NTLM
OPIE: $ENABLE_OPIE
POSIX xattr: $ENABLE_XATTR
Debugging: $ENABLE_DEBUG
Assertions: $ENABLE_ASSERTION
Valgrind: $VALGRIND_INFO
Metalink: $with_metalink
Resolver: $RESOLVER_INFO
GPGME: $have_gpg
IRI: $iri
])

View File

@@ -12,7 +12,7 @@ if [ $CORES -lt 1 ]; then CORES=1; fi
echo "Running: make distclean"
make distclean > /dev/null || true
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 -O0 -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

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 -O0 -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

@@ -57,7 +57,8 @@ 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@" --utf8 $? > $@
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" --utf8 $? > $@ || \
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" $? > $@
#wget.cat: $(MAN)
# nroff -man $? > $@

233
doc/metalink-standard.txt Normal file
View File

@@ -0,0 +1,233 @@
GNU Wget Metalink recommended behaviour
Metalink/XML and Metalink/HTTP standard reference
1. Security features
********************
Only metalink:file elements with safe "name" fields shall be accepted
[1 #section-4.1.2.1]. If unsafe metalink:file elements are saved, any
related test shall fail (see '2. Tests').
By design, libmetalink rejects unsafe metalink:file elements [3]:
* lib/metalink_helper.c (metalink_check_safe_path): Verify path
1.1 Exceptions
==============
The option --directory-prefix could allow to use an absolute, relative
or home path.
2. Tests
********
Saving a file to an unexpected path poses a security problem. We must
ensure that Wget's automated tests never modify the root and the home
paths or descend/escalate to a relative path unexpectedly.
2.1 Metalink/XML implemented tests
==================================
See testenv/Makefile.am (METALINK_TESTS).
2.2 Metalink/HTTP implemented tests
===================================
See testenv/Makefile.am (METALINK_TESTS).
3. Download file name
*********************
The download file name shall be decided by precise rules which prevent
any naming uncertainty and security issues.
3.1 Naming rules
================
The final name of downloaded files is computed starting from a trusted
name, which is then combined with the "Directory Options". The result
is verified and eventually made safer following security rules. If the
final name isn't found safe enough, then the file isn't downloaded.
Depending on the options used, a suffix could be appended to the final
name to not overwrite existing files.
3.1.1 The trusted name
======================
The option --trust-server-names decides what is the trusted name.
Any Metalink/XML element with an unsafe metalink:file "name" field is
ignored, see '1. Security features'.
3.1.1.1 Without --trust-server-names
====================================
When --trust-server-names is off, the basename of the --input-metalink
file, if available, or of the mother URL is trusted. This trusted name
is the radix of any subsequent file name.
When a Metalink/HTTP in encountered, any fetched Metalink/XML file has
its own ordinal number appended as suffix to the trusted name. In this
case scenario, an unique Metalink/XML file is saved each time applying
an additional suffix to the currently computed name when necessary.
The files described by a Metalink/XML file will be named sequentially
applying an additional suffix to the currently trusted/computed name.
3.1.1.2 With --trust-server-names
=================================
When --trust-server-names is on, the metalink:file "name" field parsed
from Metalink/XML files is trusted. When no Metalink/XML is available,
the mother URL is trusted.
Any Metalink/HTTP application/metalink4+xml file is saved using the
basename of its own Link header "name" field, if available.
In conjunction with the option --content-disposition, a 'Content-Type:
application/metalink4+xml' file is saved using the basename of its own
Content-Disposition header "filename" field, if available.
3.1.2 The final name
====================
The "Directory Options" are combined with the trusted name. The result
is evaluated again by the '1. Security features'. If the path is found
unsafe, only the basename of the final name is considered. If this is
found unsafe too, the file is not downloaded.
4. Metalink/XML
***************
4.1 Example files
=================
See [1 #section-1.1].
cat > bugus.meta4 << EOF
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<file name="/dir/A/File1">
<size>1617</size>
<hash type="sha256">ecb3dff2648667513e31554b3ad054ccd89fce38e33367c9459ac3a285153742</hash>
<url>http://another.url/common_name</url>
<url>http://ftpmirror.gnu.org/bash/bash-4.3-patches/bash43-001</url>
</file>
<file name="dir/B/File2">
<size>1594</size>
<hash type="sha256">eee7cd7062ab29a9e4f02924d9c367264dcb8b162703f74ff6eb8f175a91502b</hash>
<url>http://another.url/again/common_name</url>
<url>http://ftpmirror.gnu.org/bash/bash-4.3-patches/bash43-002</url>
</file>
</metalink>
EOF
4.2 Command line example
========================
$ wget --input-metalink=bogus.meta4
4.3 Metalink/XML file parsing
=============================
The metalink xml file is parsed by one of the following libmetalink's
functions [3], depending upon the library configured to use:
* lib/libexpat_metalink_parser.c (metalink_parse_file): Expat [4]
* lib/libxml2_metalink_parser.c (metalink_parse_file): Libxml2 [5]
The result returned doesn't include unsafe metalink:file elements, as
stated at point '1. Security features'.
An empty result shall not be considered an error. Parsing errors will
be informed to the caller of libmetalink's metalink_parse_file().
4.4 Saving files
================
Fetched metalink:file elements shall be wrote using the unique "name"
field as file name [1 #section-4.1.2.1].
A metalink:file url's file name shall not substitute the "name" field.
Security exceptions are explained in '3. Download file name'.
4.5 Multi-Source download
=========================
Parallel range requests are allowed [1 #section-1].
5. Metalink/HTTP
****************
5.1 HTTP server
===============
The local server http://127.0.0.1 is used as reference in the course
of this chapter. Any server service capable of sending Metalink/HTTP
header answers may be used.
5.2 Command line example
========================
$ wget --metalink-over-http http://127.0.0.1/dir/file.ext
5.3 Metalink/HTTP header answer
===============================
See [2 #section-1.1].
Etag: "thvDyvhfIqlvFe+A9MYgxAfm1q5="
Link: <http://www2.example.com/example.ext>; rel=duplicate
Link: <ftp://ftp.example.com/example.ext>; rel=duplicate
Link: <http://example.com/example.ext.torrent>; rel=describedby;
type="application/x-bittorrent"
Link: <http://example.com/example.ext.meta4>; rel=describedby;
type="application/metalink4+xml"
Link: <http://example.com/example.ext.asc>; rel=describedby;
type="application/pgp-signature"
Digest: SHA-256=MWVkMWQxYTRiMzk5MDQ0MzI3NGU5NDEyZTk5OWY1ZGFmNzgyZTJlO
DYzYjRjYzFhOTlmNTQwYzI2M2QwM2U2MQ==
See [2 #section-4].
Link: <http://example.com/example.ext.torrent>; rel=describedby;
type="application/x-bittorrent"; name="differentname.ext"
Link: <http://example.com/example.ext.meta4>; rel=describedby;
type="application/metalink4+xml"
5.4 Saving files
================
When none of --output-document and/or --content-disposition is used,
the file name to wrote is computed from the cli's url hierarchy. The
purpose of the "Directory Options" is as usual, and the file name is
the cli's url file name, see wget(1).
The url followed to download the file shall not substitute the cli's
url to compute the file name to wrote, except when it redirects to a
Metalink/XML file, following the rules in '3. Download file name'.
5.5 Multi-Source download
=========================
Parallel range requests are allowed [2 #section-7].
4. References
*************
[1] The Metalink Download Description Format
https://tools.ietf.org/html/rfc5854
[2] Metalink/HTTP: Mirrors and Hashes
https://tools.ietf.org/html/rfc6249
[3] Libmetalink
https://github.com/metalink-dev/libmetalink
[4] Expat
http://www.libexpat.org
[5] Libxml2
http://xmlsoft.org

165
doc/metalink.txt Normal file
View File

@@ -0,0 +1,165 @@
GNU Wget Metalink module
Evaluation of the Metalink/XML and Metalink/HTTP implementations
1. Introduction
***************
This document, and the results contained in it, is focused over the
evaluation of the Metalink/XML and Metalink/HTTP implementations.
The "Directory Options" mentioned here are used on the command line in
conjunction with the option '--input-metalink=file' for Metalink/XML,
and '--metalink-over-http' for Metalink/HTTP.
$ wget --input-metalink=<file> [directory options]
$ wget --metalink-over-http [directory options] <url>
2. Notes
********
Tests for metalink:file names beginning with '/', '~/', './', or '../'
(e.g. "/path/file") shall be run manually due to security concerns.
3. Metalink files used as reference
***********************************
3.1 Test: metalink:file with "path/file" name format
====================================================
cat > test.meta4 << EOF
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<file name="path/file">
<size>543</size>
<hash type="sha256">d37d3965f8e1a7b16504b4273b09c392776b7e4dd17e601256c7b2fd9ce5f56e</hash>
<hash type="md5">0f6ff5cdc15603f1b81227b5a296f001</hash>
<url>http://wrongurl.really/gnu/wget/wget-1.18.tar.xz.sig</url>
<url>http://ftpmirror.gnu.org/wget/wget-1.18.tar.xz.sig</url>
<url>http://ftp.gnu.org/gnu/wget/wget-1.18.tar.xz.sig</url>
<url>http://nl.mirror.babylon.network/gnu/wget/wget-1.18.tar.xz.sig</url>
</file>
</metalink>
EOF
4. `wget --input-metalink=test.meta4`
*************************************
4.1 Implemented safety features
===============================
Any metalink:file name containing an absolute, relative, or home path
(see '2. Notes') parsed from Metalink/XML files is rejected.
This is a libmetalink's design decision implemented in the function
metalink_check_safe_path(). This feature shall not be modified.
All the above conform to the RFC5854 standard.
References:
https://tools.ietf.org/html/rfc5854#section-4.1.2.1
https://tools.ietf.org/html/rfc5854#section-4.2.8.3
4.2 File download behaviour
===========================
When a Metalink/XML file is parsed:
1. create the metalink:file "path/file" tree;
2. download the metalink:url file as "path/file";
3. verify the "path/file" size, if declared;
4. verify the "path/file" checksum.
All the above conform to the RFC5854 standard.
References:
https://tools.ietf.org/html/rfc5854
4.3 Questionable behaviours
===========================
If more metalink:file elements are the same, wget downloads them all.
5. `wget --metalink-over-http`
******************************
5.1 Implemented safety features
===============================
The function url_file_name() is responsible of parsing the url's file
name and mixing in the "Directory Options" wrote on the command line.
The use of libmetalink's metalink_check_safe_path() shouldn't be
necessary (see '4.1 Implemented safety features').
All the above comform to the usual Wget's download behaviour.
References:
wget(1)
5.2 File download behaviour
===========================
When a Metalink/HTTP header is parsed:
1. extract metalink metadata from the header;
2. download the file from the mirror with the highest priority;
3. verify the file's size, if declared;
4. verify the file's checksum.
All the above comform to the usual Wget's download behaviour and to
the RFC6249 standard.
References:
wget(1)
https://tools.ietf.org/html/rfc6249
6. Directory Options
********************
'-nd'
'--no-directories'
Do not apply to Metalink/XML files (aka --input-metalink=<file>).
Apply to Metalink/HTTP urls as described in the Wget's manual, see
wget(1). The target url is the url wrote on the command line.
'-x'
'--force-directories'
Do not apply to Metalink/XML files (aka --input-metalink=<file>).
Apply to Metalink/HTTP urls as described in the Wget's manual, see
wget(1). The target url is the url wrote on the command line.
'-nH'
'--no-host-directories'
Do not apply to Metalink/XML files (aka --input-metalink=<file>).
Apply to Metalink/HTTP urls as described in the Wget's manual, see
wget(1). The target url is the url wrote on the command line.
'--protocol-directories'
Do not apply to Metalink/XML files (aka --input-metalink=<file>).
Apply to Metalink/HTTP urls as described in the Wget's manual, see
wget(1). The target url is the url wrote on the command line.
'--cut-dirs=number'
Do not apply to Metalink/XML files (aka --input-metalink=<file>).
Apply to Metalink/HTTP urls as described in the Wget's manual, see
wget(1). The target url is the url wrote on the command line.
'-P prefix'
'--directory-prefix=prefix'
Set the top of the retrieval tree to prefix for both Metalink/XML
and Metalink/HTTP downloads, see wget(1).
If combining the prefix with the file name results in an absolute,
relative, or home path, the directory components are stripped and
only the basename is used. See '4.1 Implemented safety features'.

View File

@@ -512,11 +512,27 @@ href if none was specified.
Downloads files covered in local Metalink @var{file}. Metalink version 3
and 4 are supported.
@cindex keep-badhash
@item --keep-badhash
Keeps downloaded Metalink's files with a bad hash. It appends .badhash
to the name of Metalink's files which have a checksum mismatch, except
without overwriting existing files.
@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.
Enables @samp{Content-Type: application/metalink4+xml} files download/processing.
@cindex metalink-index
@item --metalink-index=@var{number}
Set the Metalink @samp{application/metalink4+xml} metaurl ordinal
NUMBER. From 1 to the total number of ``application/metalink4+xml''
available. Specify 0 or @samp{inf} to choose the first good one.
Metaurls, such as those from a @samp{--metalink-over-http}, may have
been sorted by priority key's value; keep this in mind to choose the
right NUMBER.
@cindex preferred-location
@item --preferred-location
@@ -571,6 +587,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
@@ -694,13 +731,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
@@ -783,7 +818,7 @@ With @samp{--progress=bar}, there are currently two possible parameters,
@var{force} and @var{noscroll}.
When the output is not a TTY, the progress bar always falls back to ``dot'',
even if @samp{--progress=bar} was passed to Wget during invokation. This
even if @samp{--progress=bar} was passed to Wget during invocation. This
behaviour can be overridden and the ``bar'' output forced by using the ``force''
parameter as @samp{--progress=bar:force}.
@@ -983,7 +1018,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.
@@ -1135,6 +1170,15 @@ options for @sc{http} connections.
Prompt for a password for each connection established. Cannot be specified
when @samp{--password} is being used, because they are mutually exclusive.
@item --use-askpass=@var{command}
Prompt for a user and password using the specified command. If no command is
specified then the command in the environment variable WGET_ASKPASS is used.
If WGET_ASKPASS is not set then the command in the environment variable
SSH_ASKPASS is used.
You can set the default command for use-askpass in the @file{.wgetrc}. That
setting may be overridden from the command line.
@cindex iri support
@cindex idn support
@item --no-iri
@@ -1308,10 +1352,10 @@ the @code{digest}, or the Windows @code{NTLM} authentication scheme.
Another way to specify username and password is in the @sc{url} itself
(@pxref{URL Format}). Either method reveals your password to anyone who
bothers to run @code{ps}. To prevent the passwords from being seen,
store them in @file{.wgetrc} or @file{.netrc}, and make sure to protect
those files from other users with @code{chmod}. If the passwords are
really important, do not leave them lying in those files either---edit
the files and delete them after Wget has started the download.
use the @samp{--use-askpass} or store them in @file{.wgetrc} or @file{.netrc},
and make sure to protect those files from other users with @code{chmod}. If
the passwords are really important, do not leave them lying in those files
either---edit the files and delete them after Wget has started the download.
@iftex
@xref{Security Considerations}, for more information about security
@@ -1586,11 +1630,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
@@ -1643,6 +1687,10 @@ This option is useful for some file-downloading CGI programs that use
@code{Content-Disposition} headers to describe what the name of a
downloaded file should be.
When combined with @samp{--metalink-over-http} and @samp{--trust-server-names},
a @samp{Content-Type: application/metalink4+xml} file is named using the
@code{Content-Disposition} filename field, if available.
@cindex Content On Error
@item --content-on-error
@@ -1652,9 +1700,11 @@ with a http status code that indicates error.
@cindex Trust server names
@item --trust-server-names
If this is set to on, on a redirect the last component of the
redirection URL will be used as the local file name. By default it is
used the last component in the original URL.
If this is set, on a redirect, the local file name will be based
on the redirection URL. By default the local file name is based on
the original URL. When doing recursive retrieving this can be helpful
because in many web sites redirected URLs correspond to an underlying
file structure, while link URLs do not.
@cindex authentication
@item --auth-no-challenge
@@ -1725,6 +1775,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}
@@ -1772,6 +1828,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}
@@ -2555,11 +2623,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,
@@ -2799,7 +2867,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
@@ -3162,8 +3230,8 @@ Turn on recognition of the (non-standard) @samp{Content-Disposition}
HTTP header---if set to @samp{on}, the same as @samp{--content-disposition}.
@item trust_server_names = on/off
If set to on, use the last component of a redirection URL for the local
file name.
If set to on, construct the local file name from redirection URLs
rather than original URLs.
@item continue = on/off
If set to on, force continuation of preexistent partially retrieved
@@ -3669,7 +3737,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
@@ -3677,7 +3745,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
@@ -3687,22 +3755,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
@@ -3731,12 +3799,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
@@ -3752,7 +3820,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
@@ -3760,7 +3828,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
@@ -3797,7 +3865,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
@@ -3809,7 +3877,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
@@ -3822,13 +3890,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
@@ -3935,14 +4003,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/}.
@@ -3956,14 +4024,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
@@ -3971,15 +4039,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
@@ -3991,7 +4051,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}).
@@ -4020,7 +4080,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.
@@ -4037,7 +4097,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.
@@ -4102,7 +4162,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
@@ -4180,23 +4240,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.

2
gnulib

Submodule gnulib updated: 9c919a0643...916a632413

View File

@@ -27,89 +27,6 @@ dnl Corresponding Source for a non-source form of such a combination
dnl shall include the source code for the parts of OpenSSL used as well
dnl as that of the covered work.
dnl
dnl Check for `struct utimbuf'.
dnl
AC_DEFUN([WGET_STRUCT_UTIMBUF], [
AC_CHECK_TYPES([struct utimbuf], [], [], [
#include <stdio.h>
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_UTIME_H
# include <utime.h>
#endif
])
])
dnl Check whether fnmatch.h can be included. This doesn't use
dnl AC_FUNC_FNMATCH because Wget is already careful to only use
dnl fnmatch on certain OS'es. However, fnmatch.h is sometimes broken
dnl even on those because Apache installs its own fnmatch.h to
dnl /usr/local/include (!), which GCC uses before /usr/include.
AC_DEFUN([WGET_FNMATCH], [
AC_MSG_CHECKING([for working fnmatch.h])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([#include <fnmatch.h>
])], [
AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_WORKING_FNMATCH_H], 1,
[Define if fnmatch.h can be included.])
], [
AC_MSG_RESULT(no)
])
])
dnl Check for nanosleep. For nanosleep to work on Solaris, we must
dnl link with -lrt (recently) or with -lposix4 (older releases).
AC_DEFUN([WGET_NANOSLEEP], [
AC_CHECK_FUNCS(nanosleep, [], [
AC_CHECK_LIB(rt, nanosleep, [
AC_DEFINE([HAVE_NANOSLEEP], 1,
[Define if you have the nanosleep function.])
LIBS="-lrt $LIBS"
], [
AC_CHECK_LIB(posix4, nanosleep, [
AC_DEFINE([HAVE_NANOSLEEP], 1,
[Define if you have the nanosleep function.])
LIBS="-lposix4 $LIBS"
])
])
])
])
AC_DEFUN([WGET_POSIX_CLOCK], [
AC_CHECK_FUNCS(clock_gettime, [], [
AC_CHECK_LIB(rt, clock_gettime)
])
])
dnl Check whether we need to link with -lnsl and -lsocket, as is the
dnl case on e.g. Solaris.
AC_DEFUN([WGET_NSL_SOCKET], [
dnl On Solaris, -lnsl is needed to use gethostbyname. But checking
dnl for gethostbyname is not enough because on "NCR MP-RAS 3.0"
dnl gethostbyname is in libc, but -lnsl is still needed to use
dnl -lsocket, as well as for functions such as inet_ntoa. We look
dnl for such known offenders and if one of them is not found, we
dnl check if -lnsl is needed.
wget_check_in_nsl=NONE
AC_CHECK_FUNCS(gethostbyname, [], [
wget_check_in_nsl=gethostbyname
])
AC_CHECK_FUNCS(inet_ntoa, [], [
wget_check_in_nsl=inet_ntoa
])
if test $wget_check_in_nsl != NONE; then
AC_CHECK_LIB(nsl, $wget_check_in_nsl)
fi
AC_CHECK_LIB(socket, socket)
])
dnl ************************************************************
dnl START OF IPv6 AUTOCONFIGURATION SUPPORT MACROS
dnl ************************************************************

View File

@@ -39,9 +39,12 @@ if METALINK_IS_ENABLED
METALINK_OBJ = metalink.c
endif
if WITH_XATTR
XATTR_OBJ = xattr.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)
EXTRA_DIST = css.l css.c css_.c build_info.c.in
@@ -50,17 +53,20 @@ 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 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 \
recur.c res.c retr.c spider.c url.c warc.c $(XATTR_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 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 metalink.h
exits.h version.h metalink.h xattr.h
nodist_wget_SOURCES = version.c
EXTRA_wget_SOURCES = iri.c
LDADD = $(LIBOBJS) ../lib/libgnu.a
LDADD = $(LIBOBJS) ../lib/libgnu.a $(GETADDRINFO_LIB) $(HOSTENT_LIB)\
$(INET_NTOP_LIB) $(LIBSOCKET) $(LIB_CLOCK_GETTIME) $(LIB_CRYPTO)\
$(LIB_NANOSLEEP) $(LIB_POSIX_SPAWN) $(LIB_SELECT) $(LTLIBICONV) $(LTLIBINTL)\
$(LTLIBTHREAD) $(LTLIBUNISTRING) $(SERVENT_LIB)
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib

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

@@ -31,6 +31,7 @@ as that of the covered work. */
#include "wget.h"
#include "exits.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -56,7 +57,7 @@ as that of the covered work. */
#include <sys/time.h>
#ifdef ENABLE_IRI
#include <idn-free.h>
#include <idn2.h>
#endif
#include "utils.h"
@@ -283,7 +284,7 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
str = xmalloc (len);
snprintf (str, len, "%s (%s)", name, print);
str[len-1] = '\0';
idn_free (name);
idn2_free (name);
}
logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "),
@@ -331,8 +332,10 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
if (bufsize < 512)
bufsize = 512; /* avoid pathologically small values */
#ifdef SO_RCVBUF
setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
(void *)&bufsize, (socklen_t)sizeof (bufsize));
if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
(void *) &bufsize, (socklen_t) sizeof (bufsize)))
logprintf (LOG_NOTQUIET, _("setsockopt SO_RCVBUF failed: %s\n"),
strerror (errno));
#endif
/* When we add limit_rate support for writing, which is useful
for POST, we should also set SO_SNDBUF here. */
@@ -369,7 +372,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;
@@ -464,7 +474,9 @@ bind_local (const ip_address *bind_address, int *port)
return -1;
#ifdef SO_REUSEADDR
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, setopt_ptr, setopt_size);
if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, setopt_ptr, setopt_size))
logprintf (LOG_NOTQUIET, _("setsockopt SO_REUSEADDR failed: %s\n"),
strerror (errno));
#endif
xzero (ss);
@@ -682,6 +694,11 @@ select_fd (int fd, double maxtime, int wait_for)
struct timeval tmout;
int result;
if (fd >= FD_SETSIZE)
{
logprintf (LOG_NOTQUIET, _("Too many fds open. Cannot use select on a fd >= %d\n"), FD_SETSIZE);
exit (WGET_EXIT_GENERIC_ERROR);
}
FD_ZERO (&fdset);
FD_SET (fd, &fdset);
if (wait_for & WAIT_FOR_READ)
@@ -724,6 +741,11 @@ test_socket_open (int sock)
struct timeval to;
int ret = 0;
if (sock >= FD_SETSIZE)
{
logprintf (LOG_NOTQUIET, _("Too many fds open. Cannot use select on a fd >= %d\n"), FD_SETSIZE);
exit (WGET_EXIT_GENERIC_ERROR);
}
/* Check if we still have a valid (non-EOF) connection. From Andrew
* Maholski's code in the Unix Socket FAQ. */

View File

@@ -308,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);
@@ -329,7 +329,7 @@ convert_links (const char *file, struct urlpos *links)
char *newname = convert_basename (p, link);
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);
@@ -352,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);

View File

@@ -69,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

@@ -45,6 +45,7 @@ as that of the covered work. */
#include "wget.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -525,19 +526,51 @@ check_domain_match (const char *cookie_domain, const char *host)
{
#ifdef HAVE_LIBPSL
static int init_psl;
static const psl_ctx_t *psl;
char *cookie_domain_lower = NULL;
char *host_lower = NULL;
const psl_ctx_t *psl;
int is_acceptable;
DEBUGP (("cdm: 1"));
if (!(psl = psl_builtin()))
DEBUGP (("cdm: 1\n"));
if (!init_psl)
{
DEBUGP (("\nlibpsl not built with a public suffix list. "
"Falling back to simple heuristics.\n"));
goto no_psl;
}
init_psl = 1;
#ifdef HAVE_PSL_LATEST
if ((psl = psl_latest (NULL)))
goto have_psl;
DEBUGP (("\nPSL: Failed to load any PSL data. "
"Falling back to insecure heuristics.\n"));
#else
if ((psl = psl_builtin ()) && !psl_builtin_outdated ())
goto have_psl;
DEBUGP (("\nPSL: built-in data outdated. "
"Trying to load data from %s.\n",
quote (psl_builtin_filename ())));
if ((psl = psl_load_file (psl_builtin_filename ())))
goto have_psl;
DEBUGP (("\nPSL: %s not found or not readable. "
"Falling back to built-in data.\n",
quote (psl_builtin_filename ())));
if (!(psl = psl_builtin ()))
{
DEBUGP (("\nPSL: libpsl not built with a public suffix list. "
"Falling back to insecure heuristics.\n"));
goto no_psl;
}
#endif
}
else if (!psl)
goto no_psl;
have_psl:
if (psl_str_to_utf8lower (cookie_domain, NULL, NULL, &cookie_domain_lower) == PSL_SUCCESS &&
psl_str_to_utf8lower (host, NULL, NULL, &host_lower) == PSL_SUCCESS)
{
@@ -562,13 +595,13 @@ no_psl:
#endif
/* For efficiency make some elementary checks first */
DEBUGP (("cdm: 2"));
DEBUGP (("cdm: 2\n"));
/* For the sake of efficiency, check for exact match first. */
if (0 == strcasecmp (cookie_domain, host))
return true;
DEBUGP ((" 3"));
DEBUGP (("cdm: 3\n"));
/* HOST must match the tail of cookie_domain. */
if (!match_tail (host, cookie_domain, true))
@@ -608,7 +641,7 @@ no_psl:
if (*p == '.')
/* Ignore leading period in this calculation. */
++p;
DEBUGP ((" 4"));
DEBUGP (("cdm: 4\n"));
for (out = 0; !out; p++)
switch (*p)
{
@@ -634,12 +667,12 @@ no_psl:
++ldcl;
}
DEBUGP ((" 5"));
DEBUGP (("cdm: 5\n"));
if (dccount < 2)
return false;
DEBUGP ((" 6"));
DEBUGP (("cdm: 6\n"));
if (dccount == 2)
{
@@ -659,7 +692,7 @@ no_psl:
}
}
DEBUGP ((" 7"));
DEBUGP (("cdm: 7\n"));
/* Don't allow the host "foobar.com" to set a cookie for domain
"bar.com". */
@@ -674,7 +707,7 @@ no_psl:
return false;
}
DEBUGP ((" 8"));
DEBUGP (("cdm: 8\n"));
return true;
}
@@ -1018,7 +1051,7 @@ cookie_header (struct cookie_jar *jar, const char *host,
struct cookie *cookie;
struct weighed_cookie *outgoing;
int count, i, ocnt;
size_t count, i, ocnt;
char *result;
int result_size, pos;
PREPEND_SLASH (path); /* see cookie_handle_set_cookie */
@@ -1032,7 +1065,7 @@ cookie_header (struct cookie_jar *jar, const char *host,
chain_count = find_chains_of_host (jar, host, chains);
/* No cookies for this host. */
if (!chain_count)
if (chain_count <= 0)
return NULL;
cookies_now = time (NULL);
@@ -1043,7 +1076,7 @@ cookie_header (struct cookie_jar *jar, const char *host,
/* Count the number of matching cookies. */
count = 0;
for (i = 0; i < chain_count; i++)
for (i = 0; i < (unsigned) chain_count; i++)
for (cookie = chains[i]; cookie; cookie = cookie->next)
if (cookie_matches_url (cookie, host, port, path, secflag, NULL))
++count;
@@ -1051,12 +1084,14 @@ cookie_header (struct cookie_jar *jar, const char *host,
return NULL; /* no cookies matched */
/* Allocate the array. */
outgoing = alloca_array (struct weighed_cookie, count);
if (count > SIZE_MAX / sizeof (struct weighed_cookie))
return NULL; /* unable to process so many cookies */
outgoing = xmalloc (count * sizeof (struct weighed_cookie));
/* Fill the array with all the matching cookies from the chains that
match HOST. */
ocnt = 0;
for (i = 0; i < chain_count; i++)
for (i = 0; i < (unsigned) chain_count; i++)
for (cookie = chains[i]; cookie; cookie = cookie->next)
{
int pg;
@@ -1111,6 +1146,7 @@ cookie_header (struct cookie_jar *jar, const char *host,
}
}
result[pos++] = '\0';
xfree (outgoing);
assert (pos == result_size);
return result;
}

View File

@@ -59,6 +59,7 @@ extern char *yytext;
extern int yyleng;
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern YY_BUFFER_STATE yy_scan_bytes (const char *bytes,int len );
extern void yy_delete_buffer (YY_BUFFER_STATE b);
extern int yylex (void);
/*
@@ -109,9 +110,10 @@ get_urls_css (struct map_context *ctx, int offset, int buf_length)
int buffer_pos = 0;
int pos, length;
char *uri;
YY_BUFFER_STATE b;
/* tell flex to scan from this buffer */
yy_scan_bytes (ctx->text + offset, buf_length);
b = yy_scan_bytes (ctx->text + offset, buf_length);
while((token = yylex()) != CSSEOF)
{
@@ -188,6 +190,9 @@ get_urls_css (struct map_context *ctx, int offset, int buf_length)
}
buffer_pos += yyleng;
}
yy_delete_buffer(b);
DEBUGP (("\n"));
}

View File

@@ -31,7 +31,6 @@ as that of the covered work. */
#ifndef CSS_URL_H
#define CSS_URL_H
void get_urls_css (struct map_context *, int, int);
void get_urls_css (struct map_context *, int, int);
struct urlpos *get_urls_css_file (const char *, const char *);

View File

@@ -429,6 +429,65 @@ ip_address_to_eprt_repr (const ip_address *addr, int port, char *buf,
buf[buflen - 1] = '\0';
}
/* Bind a port and send the appropriate PORT command to the FTP
server. Use acceptport after RETR, to get the socket of data
connection. */
uerr_t
ftp_eprt (int csock, int *local_sock)
{
uerr_t err;
char *request, *respline;
ip_address addr;
int nwritten;
int port;
/* Must contain the argument of EPRT (of the form |af|addr|port|).
* 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
* 1 char for af (1-2) and 5 chars for port (0-65535) */
char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
/* Get the address of this side of the connection. */
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
return FTPSYSERR;
/* Setting port to 0 lets the system choose a free port. */
port = 0;
/* Bind the port. */
*local_sock = bind_local (&addr, &port);
if (*local_sock < 0)
return FTPSYSERR;
/* Construct the argument of EPRT (of the form |af|addr|port|). */
ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
/* Send PORT request. */
request = ftp_request ("EPRT", bytes);
nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
fd_close (*local_sock);
return WRITEFAILED;
}
xfree (request);
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
fd_close (*local_sock);
return err;
}
if (*respline != '2')
{
xfree (respline);
fd_close (*local_sock);
return FTPPORTERR;
}
xfree (respline);
return FTPOK;
}
#endif
#ifdef HAVE_SSL
/*
* The following three functions defined into this #ifdef block
@@ -542,65 +601,6 @@ bail:
}
#endif /* HAVE_SSL */
/* Bind a port and send the appropriate PORT command to the FTP
server. Use acceptport after RETR, to get the socket of data
connection. */
uerr_t
ftp_eprt (int csock, int *local_sock)
{
uerr_t err;
char *request, *respline;
ip_address addr;
int nwritten;
int port;
/* Must contain the argument of EPRT (of the form |af|addr|port|).
* 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr
* 1 char for af (1-2) and 5 chars for port (0-65535) */
char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
/* Get the address of this side of the connection. */
if (!socket_ip_address (csock, &addr, ENDPOINT_LOCAL))
return FTPSYSERR;
/* Setting port to 0 lets the system choose a free port. */
port = 0;
/* Bind the port. */
*local_sock = bind_local (&addr, &port);
if (*local_sock < 0)
return FTPSYSERR;
/* Construct the argument of EPRT (of the form |af|addr|port|). */
ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
/* Send PORT request. */
request = ftp_request ("EPRT", bytes);
nwritten = fd_write (csock, request, strlen (request), -1);
if (nwritten < 0)
{
xfree (request);
fd_close (*local_sock);
return WRITEFAILED;
}
xfree (request);
/* Get appropriate response. */
err = ftp_response (csock, &respline);
if (err != FTPOK)
{
fd_close (*local_sock);
return err;
}
if (*respline != '2')
{
xfree (respline);
fd_close (*local_sock);
return FTPPORTERR;
}
xfree (respline);
return FTPOK;
}
#endif
/* 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

@@ -167,12 +167,12 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
/*cur.perms = 1023;*/ /* #### What is this? --hniksic */
cur.perms = 0644;
}
DEBUGP (("implicit perms %0o; ", cur.perms));
DEBUGP (("implicit perms %0o; ", (unsigned) cur.perms));
}
else
{
cur.perms = symperms (tok + 1);
DEBUGP (("perms %0o; ", cur.perms));
DEBUGP (("perms %0o; ", (unsigned) cur.perms));
}
error = ignore = 0; /* Erroneous and ignoring entries are
@@ -478,6 +478,7 @@ ftp_parse_winnt_ls (const char *file)
}
/* Now it is possible to determine the position of the first symbol in
filename. */
memset(&cur, 0, sizeof (cur));
cur.name = xstrdup(filename);
DEBUGP (("Name: '%s'\n", cur.name));
@@ -931,7 +932,7 @@ ftp_parse_vms_ls (const char *file)
}
}
cur.perms = perms;
DEBUGP (("Prot. perms = %0o.\n", cur.perms));
DEBUGP (("Prot. perms = %0o.\n", (unsigned) cur.perms));
}
else
{

168
src/ftp.c
View File

@@ -52,6 +52,9 @@ as that of the covered work. */
#include "recur.h" /* for INFINITE_RECURSION */
#include "warc.h"
#include "c-strcase.h"
#ifdef ENABLE_XATTR
#include "xattr.h"
#endif
#ifdef __VMS
# include "vms.h"
@@ -236,10 +239,10 @@ 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)
get_ftp_greeting (int csock, ccon *con)
{
uerr_t err = 0;
@@ -315,13 +318,14 @@ init_control_ssl_connection (int csock, struct url *u, bool *using_control_secur
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;
@@ -355,12 +359,35 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
*qtyread = restval;
user = u->user;
passwd = u->passwd;
search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);
/* Find the username with priority */
if (u->user)
user = u->user;
else if (opt.user && (opt.use_askpass || opt.ask_passwd))
user = opt.user;
else if (opt.ftp_user)
user = opt.ftp_user;
else if (opt.user)
user = opt.user;
else
user = NULL;
/* Find the password with priority */
if (u->passwd)
passwd = u->passwd;
else if (opt.passwd && (opt.use_askpass || opt.ask_passwd))
passwd = opt.passwd;
else if (opt.ftp_passwd)
passwd = opt.ftp_passwd;
else if (opt.passwd)
passwd = opt.passwd;
else
passwd = NULL;
/* Check for ~/.netrc if none of the above match */
if (opt.netrc && (!user || !passwd))
search_netrc (u->host, (const char **) &user, (const char **) &passwd, 1);
if (!user) user = "anonymous";
passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);
if (!passwd) passwd = "-wget@";
dtsock = -1;
@@ -393,7 +420,9 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
if (!(cmd & DO_LOGIN))
{
csock = con->csock;
#ifdef HAVE_SSL
using_data_security = con->st & DATA_CHANNEL_SECURITY;
#endif
}
else /* cmd & DO_LOGIN */
{
@@ -532,10 +561,10 @@ Error in server response, closing control connection.\n"));
logputs (LOG_VERBOSE, "done.");
if (!opt.server_response)
logprintf (LOG_VERBOSE, " ==> PROT %c ... ", prot);
logprintf (LOG_VERBOSE, " ==> PROT %c ... ", (int) prot);
if ((err = ftp_prot (csock, prot)) == FTPNOPROT)
{
logprintf (LOG_NOTQUIET, _("Server did not accept the 'PROT %c' command.\n"), prot);
logprintf (LOG_NOTQUIET, _("Server did not accept the 'PROT %c' command.\n"), (int) prot);
return err;
}
if (!opt.server_response)
@@ -869,7 +898,7 @@ Error in server response, closing control connection.\n"));
Unlike the rest of this block, this particular behavior
_is_ VMS-specific, so it gets its own VMS test.
*/
if ((con->rs == ST_VMS) && (strchr( target, '/') != NULL))
if ((con->rs == ST_VMS) && (strchr (target, '/') != NULL))
{
cwd_end = 3;
DEBUGP (("Using extra \"CWD []\" step for VMS server.\n"));
@@ -1185,8 +1214,9 @@ Error in server response, closing control connection.\n"));
if (opt.spider)
{
bool exists = false;
bool all_exist = true;
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
@@ -1200,6 +1230,8 @@ Error in server response, closing control connection.\n"));
{
exists = true;
break;
} else {
all_exist = false;
}
f = f->next;
}
@@ -1220,7 +1252,11 @@ Error in server response, closing control connection.\n"));
con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return RETRFINISHED;
if (all_exist) {
return RETRFINISHED;
} else {
return FTPNSFOD;
}
}
if (opt.verbose)
@@ -1512,8 +1548,9 @@ Error in server response, closing control connection.\n"));
{
fd_close (csock);
fd_close (dtsock);
err = CONERROR;
logputs (LOG_NOTQUIET, "Could not perform SSL handshake.\n");
return CONERROR;
goto exit_error;
}
}
else
@@ -1523,7 +1560,8 @@ Error in server response, closing control connection.\n"));
{
fd_close (csock);
fd_close (dtsock);
return CONERROR;
err = CONERROR;
goto exit_error;
}
}
#endif
@@ -1541,6 +1579,11 @@ Error in server response, closing control connection.\n"));
tmrate = retr_rate (rd_size, con->dltime);
total_download_time += con->dltime;
#ifdef ENABLE_XATTR
if (opt.enable_xattr)
set_file_metadata (u->url, NULL, fp);
#endif
fd_close (local_sock);
/* Close the local file. */
if (!output_stream || con->cmd & DO_LIST)
@@ -1636,10 +1679,10 @@ Error in server response, closing control connection.\n"));
#ifdef __VMS
char *targ;
targ = ods_conform( con->target);
targ = ods_conform (con->target);
if (targ != con->target)
{
xfree( con->target);
xfree (con->target);
con->target = targ;
}
#endif /* def __VMS */
@@ -1760,6 +1803,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
@@ -1768,15 +1818,15 @@ 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,
bool force_full_retrieve)
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;
char *tms, *locf;
const char *tmrate = NULL;
uerr_t err;
struct_stat st;
struct stat st;
/* Declare WARC variables. */
bool warc_enabled = (opt.warc_filename != NULL);
@@ -1794,7 +1844,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
@@ -1912,8 +1962,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;
@@ -2081,7 +2131,8 @@ Removing file due to --delete-after in ftp_loop_internal():\n"));
/* 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 */
@@ -2102,7 +2153,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, false);
err = ftp_loop_internal (u, original_url, NULL, con, NULL, false);
lf = xstrdup (con->target);
xfree (con->target);
con->target = old_target;
@@ -2125,8 +2176,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);
@@ -2138,7 +2190,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;
@@ -2196,7 +2249,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
dlthis = true;
if (opt.timestamping && f->type == FT_PLAINFILE)
{
struct_stat st;
struct stat st;
/* If conversion of HTML files retrieved via FTP is ever implemented,
we'll need to stat() <file>.orig here when -K has been specified.
I'm not implementing it now since files on an FTP server are much
@@ -2259,7 +2312,7 @@ The sizes do not match (local %s) -- retrieving.\n\n"),
_("Invalid name of the symlink, skipping.\n"));
else
{
struct_stat st;
struct stat st;
/* Check whether we already have the correct
symbolic link. */
int rc = lstat (con->target, &st);
@@ -2299,7 +2352,10 @@ Already have correct symlink %s -> %s\n\n"),
else /* opt.retr_symlinks */
{
if (dlthis)
err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve);
{
err = ftp_loop_internal (u, original_url, f, con, NULL,
force_full_retrieve);
}
} /* opt.retr_symlinks */
break;
case FT_DIRECTORY:
@@ -2310,9 +2366,13 @@ 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, force_full_retrieve);
{
err = ftp_loop_internal (u, original_url, f, con, NULL,
force_full_retrieve);
}
break;
case FT_UNKNOWN:
default:
logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
quote (f->name));
break;
@@ -2334,7 +2394,12 @@ Already have correct symlink %s -> %s\n\n"),
(f->type == FT_PLAINFILE) && opt.preserve_perm)
{
if (f->perms)
chmod (actual_target, f->perms);
{
if (chmod (actual_target, f->perms))
logprintf (LOG_NOTQUIET,
_("Failed to set permissions for %s.\n"),
actual_target);
}
else
DEBUGP (("Unrecognized permissions for %s.\n", actual_target));
}
@@ -2375,7 +2440,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));
@@ -2388,7 +2453,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;
@@ -2438,7 +2504,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);
@@ -2481,7 +2547,7 @@ is_invalid_entry (struct fileinfo *f)
while (cur->next)
{
cur = cur->next;
if (strcmp(f_name, cur->name) == 0)
if (strcmp (f_name, cur->name) == 0)
return true;
}
return false;
@@ -2497,14 +2563,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
@@ -2600,7 +2667,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
{
@@ -2616,7 +2683,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, false);
res = ftp_loop_internal (u, original_url, NULL, con, NULL, false);
return res;
}
@@ -2636,8 +2703,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;
@@ -2658,22 +2725,23 @@ 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)
{
if (!opt.output_document)
{
struct_stat st;
struct stat st;
wgint sz;
if (stat (filename, &st) == 0)
sz = st.st_size;
@@ -2712,11 +2780,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, false);
{
res = ftp_loop_internal (u, original_url, NULL, &con, local_file, false);
}
}
if (res == FTPOK)
res = RETROK;

View File

@@ -169,7 +169,8 @@ enum wget_ftp_fstatus
};
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

@@ -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>
@@ -48,7 +50,7 @@ as that of the covered work. */
#include "hash.h"
#include "ssl.h"
#include <sys/fcntl.h>
#include <fcntl.h>
#ifdef WIN32
# include "w32sock.h"
@@ -496,7 +498,7 @@ _do_handshake (gnutls_session_t session, int fd, double timeout)
{
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",
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%u]: %s\n",
alert, str ? str : "(unknown)");
}
}
@@ -518,6 +520,22 @@ _do_handshake (gnutls_session_t session, int fd, double timeout)
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)
{
@@ -530,11 +548,14 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
/* 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);
gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, credentials);
#ifndef FD_TO_SOCKET
# define FD_TO_SOCKET(X) (X)
@@ -549,7 +570,8 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
switch (opt.secure_protocol)
{
case secure_protocol_auto:
err = gnutls_priority_set_direct (session, "NORMAL:%COMPAT:-VERS-SSL3.0", NULL);
err = gnutls_set_default_priority (session);
gnutls_session_enable_compatibility_mode(session);
break;
case secure_protocol_sslv2:
@@ -577,7 +599,8 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
break;
default:
logprintf (LOG_NOTQUIET, _("GnuTLS: unimplemented 'secure-protocol' option value %d\n"), opt.secure_protocol);
logprintf (LOG_NOTQUIET, _("GnuTLS: unimplemented 'secure-protocol' option value %u\n"),
(unsigned) opt.secure_protocol);
logprintf (LOG_NOTQUIET, _("Please report this issue to bug-wget@gnu.org\n"));
abort ();
}
@@ -586,6 +609,7 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
switch (opt.secure_protocol)
{
case secure_protocol_auto:
err = gnutls_set_default_priority (session);
break;
case secure_protocol_sslv2:
@@ -633,9 +657,13 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
{
if (!ctx || !ctx->session_data || gnutls_session_set_data (session, ctx->session_data->data, ctx->session_data->size))
{
/* server does not want to continue the session */
gnutls_free (ctx->session_data->data);
gnutls_free (ctx->session_data);
if (ctx && ctx->session_data)
{
/* server does not want to continue the session */
if (ctx->session_data->data)
gnutls_free (ctx->session_data->data);
gnutls_free (ctx->session_data);
}
gnutls_deinit (session);
return false;
}
@@ -667,6 +695,59 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
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))\
{\
@@ -687,6 +768,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)
@@ -711,6 +797,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)
{
@@ -745,13 +832,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);
}
@@ -762,5 +859,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

@@ -283,10 +283,10 @@ hash_table_new (int items,
/* Calculate the size that ensures that the table will store at
least ITEMS keys without the need to resize. */
size = 1 + items / HASH_MAX_FULLNESS;
size = (int) (1 + items / HASH_MAX_FULLNESS);
size = prime_size (size, &ht->prime_offset);
ht->size = size;
ht->resize_threshold = size * HASH_MAX_FULLNESS;
ht->resize_threshold = (int) (size * HASH_MAX_FULLNESS);
/*assert (ht->resize_threshold >= items);*/
ht->cells = xnew_array (struct cell, ht->size);
@@ -394,7 +394,7 @@ grow_hash_table (struct hash_table *ht)
#endif
ht->size = newsize;
ht->resize_threshold = newsize * HASH_MAX_FULLNESS;
ht->resize_threshold = (int) (newsize * HASH_MAX_FULLNESS);
cells = xnew_array (struct cell, newsize);
memset (cells, INVALID_PTR_CHAR, newsize * sizeof (struct cell));

View File

@@ -58,13 +58,14 @@ as that of the covered work. */
#include <errno.h>
#ifdef ENABLE_IRI
#include <idn-free.h>
#include <idn2.h>
#endif
#include "utils.h"
#include "host.h"
#include "url.h"
#include "hash.h"
#include "ptimer.h"
#ifndef NO_ADDRESS
# define NO_ADDRESS NO_DATA
@@ -427,14 +428,12 @@ getaddrinfo_with_timeout (const char *node, const char *service,
const char *
print_address (const ip_address *addr)
{
#ifdef ENABLE_IPV6
static char buf[64];
if (!inet_ntop (addr->family, IP_INADDR_DATA (addr), buf, sizeof buf))
snprintf (buf, sizeof buf, "<error: %s>", strerror (errno));
return buf;
#else
return inet_ntoa (addr->data.d4);
#endif
}
/* The following two functions were adapted from glibc's
@@ -649,6 +648,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
@@ -745,7 +850,7 @@ lookup_host (const char *host, int flags)
str = xmalloc (len);
snprintf (str, len, "%s (%s)", name, host);
str[len-1] = '\0';
idn_free (name);
idn2_free (name);
}
logprintf (LOG_VERBOSE, _("Resolving %s... "),
@@ -755,80 +860,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

@@ -53,6 +53,7 @@ as that of the covered work. */
struct hsts_store {
struct hash_table *table;
time_t last_mtime;
bool changed;
};
struct hsts_kh {
@@ -79,7 +80,6 @@ enum hsts_kh_match {
#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))
@@ -148,13 +148,14 @@ hsts_find_entry (hsts_store_t store,
end:
/* restore pointer or we'll get a SEGV */
k->host = org_ptr;
xfree (k->host);
/* 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;
@@ -236,8 +237,7 @@ hsts_new_entry (hsts_store_t store,
static void
hsts_remove_entry (hsts_store_t store, struct hsts_kh *kh)
{
if (hash_table_remove (store->table, kh))
xfree (kh->host);
hash_table_remove (store->table, kh);
}
static bool
@@ -316,7 +316,7 @@ hsts_store_dump (hsts_store_t store, FILE *fp)
/* Print preliminary comments. We don't care if any of these fail. */
fputs ("# HSTS 1.0 Known Hosts database for GNU Wget.\n", fp);
fputs ("# Edit at your own risk.\n", fp);
fputs ("# <hostname>[:<port>]\t<incl. subdomains>\t<created>\t<max-age>\n", fp);
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);)
@@ -326,7 +326,8 @@ hsts_store_dump (hsts_store_t store, FILE *fp)
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)
(unsigned long) khi->created,
(unsigned long) khi->max_age) < 0)
{
logprintf (LOG_ALWAYS, "Could not write the HSTS database correctly.\n");
break;
@@ -334,6 +335,30 @@ hsts_store_dump (hsts_store_t store, FILE *fp)
}
}
/*
* 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
#ifndef WINDOWS
/*
* The world-writable concept is a Unix-centric notion.
* We bypass this test on Windows.
*/
!(st.st_mode & S_IWOTH) &&
#endif
S_ISREG (st.st_mode);
}
/* HSTS API */
/*
@@ -370,14 +395,19 @@ hsts_match (hsts_store_t store, struct url *u)
if (u->port == 80)
u->port = 443;
url_changed = true;
store->changed = true;
}
}
else
hsts_remove_entry (store, kh);
{
hsts_remove_entry (store, kh);
store->changed = true;
}
}
xfree (kh->host);
}
xfree(kh);
xfree (kh);
return url_changed;
}
@@ -422,12 +452,14 @@ hsts_store_entry (hsts_store_t store,
if (entry && match == CONGRUENT_MATCH)
{
if (max_age == 0)
hsts_remove_entry (store, kh);
{
hsts_remove_entry (store, kh);
store->changed = true;
}
else if (max_age > 0)
{
entry->include_subdomains = include_subdomains;
if (entry->max_age != max_age)
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 */
@@ -435,6 +467,9 @@ hsts_store_entry (hsts_store_t store,
if (t != -1)
entry->created = t;
entry->max_age = max_age;
entry->include_subdomains = include_subdomains;
store->changed = true;
}
}
/* we ignore negative max_ages */
@@ -449,11 +484,14 @@ hsts_store_entry (hsts_store_t store,
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);
xfree (kh);
return result;
}
@@ -462,29 +500,49 @@ hsts_store_t
hsts_store_open (const char *filename)
{
hsts_store_t store = NULL;
struct stat st;
FILE *fp = NULL;
store = xnew0 (struct hsts_store);
store->table = hash_table_new (0, hsts_hash_func, hsts_cmp_func);
store->last_mtime = 0;
store->changed = false;
if (file_exists_p (filename))
{
if (stat (filename, &st) == 0)
store->last_mtime = st.st_mtime;
fp = fopen (filename, "r");
if (!fp || !hsts_read_database (store, fp, false))
if (hsts_file_access_valid (filename))
{
/* abort! */
struct stat st;
FILE *fp = fopen (filename, "r");
if (!fp || !hsts_read_database (store, fp, false))
{
/* abort! */
hsts_store_close (store);
xfree (store);
if (fp)
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");
}
if (fp)
fclose (fp);
}
out:
return store;
}
@@ -525,6 +583,12 @@ hsts_store_save (hsts_store_t store, const char *filename)
}
}
bool
hsts_store_has_changed (hsts_store_t store)
{
return (store ? store->changed : false);
}
void
hsts_store_close (hsts_store_t store)
{
@@ -613,7 +677,7 @@ test_url_rewrite (hsts_store_t s, const char *url, int port, bool rewrite)
if (rewrite)
{
if (port == 80)
mu_assert("URL: port should've been rewritten to 443", u.port == 443);
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);
@@ -686,7 +750,7 @@ test_hsts_url_rewrite_superdomain (void)
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, time(NULL) + 1234, true);
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);
@@ -707,7 +771,7 @@ test_hsts_url_rewrite_congruent (void)
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, time(NULL) + 1234, false);
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);
@@ -726,6 +790,7 @@ test_hsts_read_database (void)
char *home = home_dir();
char *file = NULL;
FILE *fp = NULL;
time_t created = time(NULL) - 10;
if (home)
{
@@ -734,9 +799,9 @@ test_hsts_read_database (void)
if (fp)
{
fputs ("# dummy comment\n", fp);
fputs ("foo.example.com\t0\t1\t1434224817\t123123123\n", fp);
fputs ("bar.example.com\t0\t0\t1434224817\t456456456\n", fp);
fputs ("test.example.com\t8080\t0\t1434224817\t789789789\n", fp);
fprintf (fp, "foo.example.com\t0\t1\t%lu\t123\n",(unsigned long) created);
fprintf (fp, "bar.example.com\t0\t0\t%lu\t456\n", (unsigned long) created);
fprintf (fp, "test.example.com\t8080\t0\t%lu\t789\n", (unsigned long) created);
fclose (fp);
table = hsts_store_open (file);

View File

@@ -43,6 +43,7 @@ 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,

View File

@@ -801,14 +801,6 @@ name_allowed (const struct hash_table *ht, const char *b, const char *e)
} \
} while (0)
/* Skip non-whitespace, if any. */
#define SKIP_NON_WS(p) do { \
while (!c_isspace (*p)) { \
ADVANCE (p); \
} \
} while (0)
#ifdef STANDALONE
static int tag_backout_count;
#endif

View File

@@ -56,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);
@@ -105,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 },
@@ -183,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;
@@ -674,6 +676,91 @@ 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);
if (up)
{
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. */
@@ -752,10 +839,13 @@ 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
xfree (meta_charset);
DEBUGP (("no-follow in %s: %d\n", file, ctx.nofollow));
if (meta_disallow_follow)

View File

@@ -122,7 +122,7 @@ ntlm_input (struct ntlmdata *ntlm, const char *header)
DEBUGP (("Received a type-2 NTLM message.\n"));
size = base64_decode (header, buffer);
size = wget_base64_decode (header, buffer);
if (size < 0)
return false; /* malformed base64 from server */
@@ -411,7 +411,7 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
size = 32 + hostlen + domlen;
base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
base64_encode (ntlmbuf, size, base64);
wget_base64_encode (ntlmbuf, size, base64);
output = concat_strings ("NTLM ", base64, (char *) 0);
break;
@@ -584,7 +584,7 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
/* convert the binary blob into base64 */
base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
base64_encode (ntlmbuf, size, base64);
wget_base64_encode (ntlmbuf, size, base64);
output = concat_strings ("NTLM ", base64, (char *) 0);

View File

@@ -39,6 +39,7 @@ as that of the covered work. */
#include <errno.h>
#include <time.h>
#include <locale.h>
#include <fcntl.h>
#include "hash.h"
#include "http.h"
@@ -66,6 +67,9 @@ as that of the covered work. */
# include "metalink.h"
# include "xstrndup.h"
#endif
#ifdef ENABLE_XATTR
#include "xattr.h"
#endif
#ifdef TESTING
#include "test.h"
@@ -341,7 +345,7 @@ request_send (const struct request *req, int fd, FILE *warc_tmp)
/* "\r\n\0" */
size += 3;
p = request_string = alloca_array (char, size);
p = request_string = xmalloc (size);
/* Generate the request. */
@@ -376,8 +380,9 @@ request_send (const struct request *req, int fd, FILE *warc_tmp)
/* Write a copy of the data to the WARC record. */
int warc_tmp_written = fwrite (request_string, 1, size - 1, warc_tmp);
if (warc_tmp_written != size - 1)
return -2;
write_error = -2;
}
xfree (request_string);
return write_error;
}
@@ -420,7 +425,7 @@ maybe_send_basic_creds (const char *hostname, const char *user,
do_challenge = true;
}
else if (basic_authed_hosts
&& hash_table_contains(basic_authed_hosts, hostname))
&& hash_table_contains (basic_authed_hosts, hostname))
{
DEBUGP (("Found %s in basic_authed_hosts.\n", quote (hostname)));
do_challenge = true;
@@ -446,9 +451,9 @@ register_basic_auth_host (const char *hostname)
{
basic_authed_hosts = make_nocase_string_hash_table (1);
}
if (!hash_table_contains(basic_authed_hosts, hostname))
if (!hash_table_contains (basic_authed_hosts, hostname))
{
hash_table_put (basic_authed_hosts, xstrdup(hostname), NULL);
hash_table_put (basic_authed_hosts, xstrdup (hostname), NULL);
DEBUGP (("Inserted %s into basic_authed_hosts\n", quote (hostname)));
}
}
@@ -846,7 +851,7 @@ resp_free (struct response **resp_ref)
caused crashes in UTF-8 locales. */
static void
print_response_line(const char *prefix, const char *b, const char *e)
print_response_line (const char *prefix, const char *b, const char *e)
{
char *copy;
BOUNDED_TO_ALLOCA(b, e, copy);
@@ -872,7 +877,7 @@ print_server_response (const struct response *resp, const char *prefix)
--e;
if (b < e && e[-1] == '\r')
--e;
print_response_line(prefix, b, e);
print_response_line (prefix, b, e);
}
}
@@ -1026,18 +1031,18 @@ skip_short_body (int fd, wgint contlen, bool chunked)
or a fragment of a long parameter value
*/
static int
modify_param_name(param_token *name)
modify_param_name (param_token *name)
{
const char *delim1 = memchr (name->b, '*', name->e - name->b);
const char *delim2 = memrchr (name->b, '*', name->e - name->b);
int result;
if(delim1 == NULL)
if (delim1 == NULL)
{
result = NOT_RFC2231;
}
else if(delim1 == delim2)
else if (delim1 == delim2)
{
if ((name->e - 1) == delim1)
{
@@ -1155,12 +1160,12 @@ extract_param (const char **source, param_token *name, param_token *value,
}
*source = p;
param_type = modify_param_name(name);
param_type = modify_param_name (name);
if (param_type != NOT_RFC2231)
{
if (param_type == RFC2231_ENCODING && is_url_encoded)
*is_url_encoded = true;
modify_param_value(value, param_type);
modify_param_value (value, param_type);
}
return true;
}
@@ -1175,8 +1180,8 @@ static void
append_value_to_filename (char **filename, param_token const * const value,
bool is_url_encoded)
{
int original_length = strlen(*filename);
int new_length = strlen(*filename) + (value->e - value->b);
int original_length = strlen (*filename);
int new_length = strlen (*filename) + (value->e - value->b);
*filename = xrealloc (*filename, new_length+1);
memcpy (*filename + original_length, value->b, (value->e - value->b));
(*filename)[new_length] = '\0';
@@ -1281,7 +1286,7 @@ parse_strict_transport_security (const char *header, time_t *max_age, bool *incl
{
if (BOUNDED_EQUAL_NO_CASE (name.b, name.e, "max-age"))
{
xfree(c_max_age);
xfree (c_max_age);
c_max_age = strdupdelim (value.b, value.e);
}
else if (BOUNDED_EQUAL_NO_CASE (name.b, name.e, "includeSubDomains"))
@@ -1564,6 +1569,7 @@ struct http_stat
#ifdef HAVE_METALINK
metalink_t *metalink;
#endif
bool temporary; /* downloading a temporary file */
};
static void
@@ -1805,7 +1811,7 @@ time_to_rfc1123 (time_t time, char *buf, size_t bufsize)
}
static struct request *
initialize_request (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
initialize_request (const struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
bool inhibit_keep_alive, bool *basic_auth_finished,
wgint *body_data_size, char **user, char **passwd, uerr_t *ret)
{
@@ -1869,21 +1875,42 @@ initialize_request (struct url *u, struct http_stat *hs, int *dt, struct url *pr
request_set_header (req, "Accept", "*/*", rel_none);
request_set_header (req, "Accept-Encoding", "identity", rel_none);
/* Find the username and password for authentication. */
*user = u->user;
*passwd = u->passwd;
search_netrc (u->host, (const char **)&user, (const char **)&passwd, 0);
*user = *user ? *user : (opt.http_user ? opt.http_user : opt.user);
*passwd = *passwd ? *passwd : (opt.http_passwd ? opt.http_passwd : opt.passwd);
/* Find the username with priority */
if (u->user)
*user = u->user;
else if (opt.user && (opt.use_askpass || opt.ask_passwd))
*user = opt.user;
else if (opt.http_user)
*user = opt.http_user;
else if (opt.user)
*user = opt.user;
else
*user = NULL;
/* Find the password with priority */
if (u->passwd)
*passwd = u->passwd;
else if (opt.passwd && (opt.use_askpass || opt.ask_passwd))
*passwd = opt.passwd;
else if (opt.http_passwd)
*passwd = opt.http_passwd;
else if (opt.passwd)
*passwd = opt.passwd;
else
*passwd = NULL;
/* Check for ~/.netrc if none of the above match */
if (opt.netrc && (!user || !passwd))
search_netrc (u->host, (const char **) user, (const char **) passwd, 0);
/* We only do "site-wide" authentication with "global" user/password
* values unless --auth-no-challange has been requested; URL user/password
* info overrides. */
if (user && *passwd && (!u->user || opt.auth_without_challenge))
if (*user && *passwd && (!u->user || opt.auth_without_challenge))
{
/* If this is a host for which we've already received a Basic
* challenge, we'll go ahead and send Basic authentication creds. */
*basic_auth_finished = maybe_send_basic_creds(u->host, *user, *passwd, req);
*basic_auth_finished = maybe_send_basic_creds (u->host, *user, *passwd, req);
}
/* Generate the Host header, HOST:PORT. Take into account that:
@@ -1951,7 +1978,7 @@ initialize_request (struct url *u, struct http_stat *hs, int *dt, struct url *pr
}
static void
initialize_proxy_configuration (struct url *u, struct request *req,
initialize_proxy_configuration (const struct url *u, struct request *req,
struct url *proxy, char **proxyauth)
{
char *proxy_user, *proxy_passwd;
@@ -1983,7 +2010,7 @@ initialize_proxy_configuration (struct url *u, struct request *req,
}
static uerr_t
establish_connection (struct url *u, struct url **conn_ref,
establish_connection (const struct url *u, const struct url **conn_ref,
struct http_stat *hs, struct url *proxy,
char **proxyauth,
struct request **req_ref, bool *using_ssl,
@@ -1993,7 +2020,7 @@ establish_connection (struct url *u, struct url **conn_ref,
bool host_lookup_failed = false;
int sock = *sock_ref;
struct request *req = *req_ref;
struct url *conn = *conn_ref;
const struct url *conn = *conn_ref;
struct response *resp;
int write_error;
int statcode;
@@ -2004,7 +2031,7 @@ establish_connection (struct url *u, struct url **conn_ref,
proxy is used. The exception is when SSL is in use, in which
case the proxy is nothing but a passthrough to the target
host, registered as a connection to the latter. */
struct url *relevant = conn;
const struct url *relevant = conn;
#ifdef HAVE_SSL
if (u->scheme == SCHEME_HTTPS)
relevant = u;
@@ -2119,7 +2146,7 @@ establish_connection (struct url *u, struct url **conn_ref,
xfree (head);
return HERR;
}
xfree(hs->message);
xfree (hs->message);
hs->message = xstrdup (message);
resp_free (&resp);
xfree (head);
@@ -2168,7 +2195,7 @@ set_file_timestamp (struct http_stat *hs)
char *filename_plus_orig_suffix = alloca (filename_len + sizeof (ORIG_SFX));
bool local_dot_orig_file_exists = false;
char *local_filename = NULL;
struct_stat st;
struct stat st;
if (opt.backup_converted)
/* If -K is specified, we'll act on the assumption that it was specified
@@ -2225,7 +2252,7 @@ set_file_timestamp (struct http_stat *hs)
}
static uerr_t
check_file_output (struct url *u, struct http_stat *hs,
check_file_output (const struct url *u, struct http_stat *hs,
struct response *resp, char *hdrval, size_t hdrsize)
{
/* Determine the local filename if needed. Notice that if -O is used
@@ -2254,6 +2281,14 @@ check_file_output (struct url *u, struct http_stat *hs,
xfree (local_file);
}
hs->temporary = opt.delete_after || opt.spider || !acceptable (hs->local_file);
if (hs->temporary)
{
char *tmp = aprintf ("%s.tmp", hs->local_file);
xfree (hs->local_file);
hs->local_file = tmp;
}
/* TODO: perform this check only once. */
if (!hs->existence_checked && file_exists_p (hs->local_file))
{
@@ -2285,7 +2320,7 @@ check_file_output (struct url *u, struct http_stat *hs,
}
static uerr_t
check_auth (struct url *u, char *user, char *passwd, struct response *resp,
check_auth (const struct url *u, char *user, char *passwd, struct response *resp,
struct request *req, bool *ntlm_seen_ref, bool *retry,
bool *basic_auth_finished_ref, bool *auth_finished_ref)
{
@@ -2467,7 +2502,15 @@ open_output_stream (struct http_stat *hs, int count, FILE **fp)
open_id = 22;
*fp = fopen (hs->local_file, "wb", FOPEN_OPT_ARGS);
#else /* def __VMS */
*fp = fopen (hs->local_file, "wb");
if (hs->temporary)
{
*fp = fdopen (open (hs->local_file, O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR), "wb");
}
else
{
*fp = fopen (hs->local_file, "wb");
}
#endif /* def __VMS [else] */
}
else
@@ -2533,7 +2576,7 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
metalink_t *metalink = NULL;
metalink_file_t *mfile = xnew0 (metalink_file_t);
const char *val_beg, *val_end;
int res_count = 0, hash_count = 0, sig_count = 0, i;
int res_count = 0, meta_count = 0, hash_count = 0, sig_count = 0, i;
DEBUGP (("Checking for Metalink in HTTP response\n"));
@@ -2546,6 +2589,88 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
/* Begin with 1-element array (for 0-termination). */
mfile->checksums = xnew0 (metalink_checksum_t *);
mfile->resources = xnew0 (metalink_resource_t *);
mfile->metaurls = xnew0 (metalink_metaurl_t *);
/* Process the Content-Type header. */
if (resp_header_locate (resp, "Content-Type", 0, &val_beg, &val_end) != -1)
{
metalink_metaurl_t murl = {0};
const char *type_beg, *type_end;
char *typestr = NULL;
char *namestr = NULL;
size_t type_len;
DEBUGP (("Processing Content-Type header...\n"));
/* Find beginning of type. */
type_beg = val_beg;
while (type_beg < val_end && c_isspace (*type_beg))
type_beg++;
/* Find end of type. */
type_end = type_beg + 1;
while (type_end < val_end &&
*type_end != ';' &&
*type_end != ' ' &&
*type_end != '\r' &&
*type_end != '\n')
type_end++;
if (type_beg >= val_end || type_end > val_end)
{
DEBUGP (("Invalid Content-Type header. Ignoring.\n"));
goto skip_content_type;
}
type_len = type_end - type_beg;
typestr = xstrndup (type_beg, type_len);
DEBUGP (("Content-Type: %s\n", typestr));
if (strcmp (typestr, "application/metalink4+xml"))
{
xfree (typestr);
goto skip_content_type;
}
/*
Valid ranges for the "pri" attribute are from
1 to 999999. Mirror servers with a lower value of the "pri"
attribute have a higher priority, while mirrors with an undefined
"pri" attribute are considered to have a value of 999999, which is
the lowest priority.
rfc6249 section 3.1
*/
murl.priority = DEFAULT_PRI;
murl.mediatype = typestr;
typestr = NULL;
if (opt.content_disposition
&& resp_header_locate (resp, "Content-Disposition", 0, &val_beg, &val_end) != -1)
{
find_key_value (val_beg, val_end, "filename", &namestr);
murl.name = namestr;
namestr = NULL;
}
murl.url = xstrdup (u->url);
DEBUGP (("URL=%s\n", murl.url));
DEBUGP (("MEDIATYPE=%s\n", murl.mediatype));
DEBUGP (("NAME=%s\n", murl.name ? murl.name : ""));
DEBUGP (("PRIORITY=%d\n", murl.priority));
/* 1 slot from new resource, 1 slot for null-termination. */
mfile->metaurls = xrealloc (mfile->metaurls,
sizeof (metalink_metaurl_t *) * (meta_count + 2));
mfile->metaurls[meta_count] = xnew0 (metalink_metaurl_t);
*mfile->metaurls[meta_count] = murl;
meta_count++;
}
skip_content_type:
/* Find all Link headers. */
for (i = 0;
@@ -2606,14 +2731,14 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
DEBUGP (("URL=%s\n", urlstr));
DEBUGP (("rel=%s\n", rel));
if (!strcmp (rel, "describedby"))
find_key_value (attrs_beg, val_end, "type", &reltype);
/* Handle signatures.
Libmetalink only supports one signature per file. Therefore we stop
as soon as we successfully get first supported signature. */
if (sig_count == 0 &&
!strcmp (rel, "describedby") &&
find_key_value (attrs_beg, val_end, "type", &reltype) &&
!strcmp (reltype, "application/pgp-signature")
)
reltype && !strcmp (reltype, "application/pgp-signature"))
{
/* Download the signature to a temporary file. */
FILE *_output_stream = output_stream;
@@ -2779,6 +2904,60 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
res_count++;
}
} /* Handle resource link (rel=duplicate). */
/* Handle Metalink/XML resources. */
else if (reltype && !strcmp (reltype, "application/metalink4+xml"))
{
metalink_metaurl_t murl = {0};
char *pristr;
/*
Valid ranges for the "pri" attribute are from
1 to 999999. Mirror servers with a lower value of the "pri"
attribute have a higher priority, while mirrors with an undefined
"pri" attribute are considered to have a value of 999999, which is
the lowest priority.
rfc6249 section 3.1
*/
murl.priority = DEFAULT_PRI;
if (find_key_value (url_end, val_end, "pri", &pristr))
{
long pri;
char *end_pristr;
/* Do not care for errno since 0 is error in this case. */
pri = strtol (pristr, &end_pristr, 10);
if (end_pristr != pristr + strlen (pristr) ||
!VALID_PRI_RANGE (pri))
{
/* This is against the specification, so let's inform the user. */
logprintf (LOG_NOTQUIET,
_("Invalid pri value. Assuming %d.\n"),
DEFAULT_PRI);
}
else
murl.priority = pri;
xfree (pristr);
}
murl.mediatype = xstrdup (reltype);
DEBUGP (("MEDIATYPE=%s\n", murl.mediatype));
/* At this point we have validated the new resource. */
find_key_value (url_end, val_end, "name", &murl.name);
murl.url = urlstr;
urlstr = NULL;
/* 1 slot from new resource, 1 slot for null-termination. */
mfile->metaurls = xrealloc (mfile->metaurls,
sizeof (metalink_metaurl_t *) * (meta_count + 2));
mfile->metaurls[meta_count] = xnew0 (metalink_metaurl_t);
*mfile->metaurls[meta_count] = murl;
meta_count++;
} /* Handle resource link (rel=describedby). */
else
DEBUGP (("This link header was not used for Metalink\n"));
@@ -2789,8 +2968,9 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
/* Null-terminate resources array. */
mfile->resources[res_count] = 0;
mfile->metaurls[meta_count] = 0;
if (res_count == 0)
if (res_count == 0 && meta_count == 0)
{
DEBUGP (("No valid metalink references found.\n"));
goto fail;
@@ -2816,9 +2996,17 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
Therefore we convert: base64 -> binary -> hex. */
const size_t dig_hash_str_len = strlen (dig_hash);
char *bin_hash = alloca (dig_hash_str_len * 3 / 4 + 1);
size_t hash_bin_len;
ssize_t hash_bin_len;
hash_bin_len = base64_decode (dig_hash, bin_hash);
hash_bin_len = wget_base64_decode (dig_hash, bin_hash);
/* Detect malformed base64 input. */
if (hash_bin_len < 0)
{
xfree (dig_type);
xfree (dig_hash);
continue;
}
/* One slot for me, one for zero-termination. */
mfile->checksums =
@@ -2827,8 +3015,8 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
mfile->checksums[hash_count] = xnew (metalink_checksum_t);
mfile->checksums[hash_count]->type = dig_type;
mfile->checksums[hash_count]->hash = xmalloc (hash_bin_len * 2 + 1);
wg_hex_to_string (mfile->checksums[hash_count]->hash, bin_hash, hash_bin_len);
mfile->checksums[hash_count]->hash = xmalloc ((size_t)hash_bin_len * 2 + 1);
wg_hex_to_string (mfile->checksums[hash_count]->hash, bin_hash, (size_t)hash_bin_len);
xfree (dig_hash);
@@ -2845,7 +3033,7 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
rfc6249 section 6
*/
if (hash_count == 0)
if (res_count && hash_count == 0)
{
logputs (LOG_VERBOSE,
_("Could not find acceptable digest for Metalink resources.\n"
@@ -2856,6 +3044,7 @@ metalink_from_http (const struct response *resp, const struct http_stat *hs,
/* Metalink data is OK. Now we just need to sort the resources based
on their priorities, preference, and perhaps location. */
stable_sort (mfile->resources, res_count, sizeof (metalink_resource_t *), metalink_res_cmp);
stable_sort (mfile->metaurls, meta_count, sizeof (metalink_metaurl_t *), metalink_meta_cmp);
/* Restore sensible preference values (in case someone cares to look). */
for (i = 0; i < res_count; ++i)
@@ -2892,8 +3081,8 @@ fail:
If PROXY is non-NULL, the connection will be made to the proxy
server, and u->url will be requested. */
static uerr_t
gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
struct iri *iri, int count)
gethttp (const struct url *u, struct url *original_url, struct http_stat *hs,
int *dt, struct url *proxy, struct iri *iri, int count)
{
struct request *req = NULL;
@@ -2903,7 +3092,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
int statcode;
int write_error;
wgint contlen, contrange;
struct url *conn;
const struct url *conn;
FILE *fp;
int err;
uerr_t retval;
@@ -2997,7 +3186,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
hs->res = -1;
hs->rderrmsg = NULL;
hs->newloc = NULL;
xfree(hs->remote_time);
xfree (hs->remote_time);
hs->error = NULL;
hs->message = NULL;
@@ -3136,7 +3325,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
bool warc_result;
/* Generate a timestamp and uuid for this request. */
warc_timestamp (warc_timestamp_str, sizeof(warc_timestamp_str));
warc_timestamp (warc_timestamp_str, sizeof (warc_timestamp_str));
warc_uuid_str (warc_request_uuid);
/* Create a request record and store it in the WARC file. */
@@ -3182,7 +3371,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
resp = resp_new (head);
/* Check for status line. */
xfree(message);
xfree (message);
statcode = resp_status (resp, &message);
if (statcode < 0)
{
@@ -3211,7 +3400,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
while (_repeat);
}
xfree(hs->message);
xfree (hs->message);
hs->message = xstrdup (message);
if (!opt.server_response)
logprintf (LOG_VERBOSE, "%2d %s\n", statcode,
@@ -3291,6 +3480,9 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
if (metalink)
{
hs->metalink = metalink_from_http (resp, hs, u);
/* Bugfix: hs->local_file is NULL (opt.content_disposition). */
if (!hs->local_file && hs->metalink && hs->metalink->origin)
hs->local_file = xstrdup (hs->metalink->origin);
xfree (hs->message);
retval = RETR_WITH_METALINK;
CLOSE_FINISH (sock);
@@ -3403,16 +3595,16 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
{
/* process strict transport security */
if (hsts_store_entry (hsts_store, u->scheme, u->host, u->port, max_age, include_subdomains))
DEBUGP(("Added new HSTS host: %s:%u (max-age: %u, includeSubdomains: %s)\n",
DEBUGP(("Added new HSTS host: %s:%u (max-age: %lu, includeSubdomains: %s)\n",
u->host,
u->port,
(unsigned int) max_age,
(unsigned) u->port,
(unsigned long) max_age,
(include_subdomains ? "true" : "false")));
else
DEBUGP(("Updated HSTS host: %s:%u (max-age: %u, includeSubdomains: %s)\n",
DEBUGP(("Updated HSTS host: %s:%u (max-age: %lu, includeSubdomains: %s)\n",
u->host,
u->port,
(unsigned int) max_age,
(unsigned) u->port,
(unsigned long) max_age,
(include_subdomains ? "true" : "false")));
}
}
@@ -3424,21 +3616,25 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
char *tmp = strchr (type, ';');
if (tmp)
{
#ifdef ENABLE_IRI
/* sXXXav: only needed if IRI support is enabled */
char *tmp2 = tmp + 1;
#endif
while (tmp > type && c_isspace (tmp[-1]))
--tmp;
*tmp = '\0';
#ifdef ENABLE_IRI
/* Try to get remote encoding if needed */
if (opt.enable_iri && !opt.encoding_remote)
{
tmp = parse_charset (tmp2);
if (tmp)
set_content_encoding (iri, tmp);
xfree(tmp);
xfree (tmp);
}
#endif
}
}
hs->newloc = resp_header_strdup (resp, "Location");
@@ -3642,7 +3838,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
goto cleanup;
}
if ((contrange != 0 && contrange != hs->restval)
|| (H_PARTIAL (statcode) && !contrange))
|| (H_PARTIAL (statcode) && !contrange && hs->restval))
{
/* The Range request was somehow misunderstood by the server.
Bail out. */
@@ -3750,6 +3946,16 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
goto cleanup;
}
#ifdef ENABLE_XATTR
if (opt.enable_xattr)
{
if (original_url != u)
set_file_metadata (u->url, original_url->url, fp);
else
set_file_metadata (u->url, NULL, fp);
}
#endif
err = read_response_body (hs, sock, fp, contlen, contrange,
chunked_transfer_encoding,
u->url, warc_timestamp_str,
@@ -3779,7 +3985,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy,
/* The genuine HTTP loop! This is the part where the retrieval is
retried, and retried, and retried, and... */
uerr_t
http_loop (struct url *u, struct url *original_url, char **newloc,
http_loop (const struct url *u, struct url *original_url, char **newloc,
char **local_file, const char *referer, int *dt, struct url *proxy,
struct iri *iri)
{
@@ -3792,9 +3998,8 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
uerr_t err, ret = TRYLIMEXC;
time_t tmr = -1; /* remote time-stamp */
struct http_stat hstat; /* HTTP status */
struct_stat st;
struct stat st;
bool send_head_first = true;
char *file_name;
bool force_full_retrieve = false;
@@ -3864,11 +4069,6 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
if (opt.content_disposition && opt.always_rest)
send_head_first = true;
if (!opt.output_document)
file_name = url_file_name (opt.trustservernames ? u : original_url, NULL);
else
file_name = xstrdup (opt.output_document);
#ifdef HAVE_METALINK
if (opt.metalink_over_http)
{
@@ -3881,7 +4081,7 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
{
/* Use conditional get request if requested
* and if timestamp is known at this moment. */
if (opt.if_modified_since && file_exists_p (file_name) && !send_head_first)
if (opt.if_modified_since && !send_head_first && got_name && file_exists_p (hstat.local_file))
{
*dt |= IF_MODIFIED_SINCE;
{
@@ -3892,12 +4092,10 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
}
/* Send preliminary HEAD request if -N is given and we have existing
* destination file or content disposition is enabled. */
else if (file_exists_p (file_name) || opt.content_disposition)
else if (opt.content_disposition || file_exists_p (hstat.local_file))
send_head_first = true;
}
xfree (file_name);
/* THE loop */
do
{
@@ -3976,7 +4174,7 @@ http_loop (struct url *u, struct url *original_url, char **newloc,
*dt &= ~SEND_NOCACHE;
/* Try fetching the document, or at least its head. */
err = gethttp (u, &hstat, dt, proxy, iri, count);
err = gethttp (u, original_url, &hstat, dt, proxy, iri, count);
/* Time? */
tms = datetime_str (time (NULL));
@@ -4404,7 +4602,10 @@ exit:
if ((ret == RETROK || opt.content_on_error) && local_file)
{
xfree (*local_file);
*local_file = xstrdup (hstat.local_file);
/* Bugfix: Prevent SIGSEGV when hstat.local_file was left NULL
(i.e. due to opt.content_disposition). */
if (hstat.local_file)
*local_file = xstrdup (hstat.local_file);
}
free_hstat (&hstat);
@@ -4550,7 +4751,7 @@ basic_authentication_encode (const char *user, const char *passwd)
sprintf (t1, "%s:%s", user, passwd);
t2 = (char *)alloca (BASE64_LENGTH (len1) + 1);
base64_encode (t1, len1, t2);
wget_base64_encode (t1, len1, t2);
return concat_strings ("Basic ", t2, (char *) 0);
}
@@ -4597,7 +4798,7 @@ digest_authentication_encode (const char *au, const char *user,
{ "algorithm", &algorithm }
};
char cnonce[16] = "";
char *res;
char *res = NULL;
int res_len;
size_t res_size;
param_token name, value;
@@ -4620,29 +4821,22 @@ digest_authentication_encode (const char *au, const char *user,
}
}
if (qop != NULL && strcmp(qop,"auth"))
if (qop && strcmp (qop, "auth"))
{
logprintf (LOG_NOTQUIET, _("Unsupported quality of protection '%s'.\n"), qop);
xfree (qop); /* force freeing mem and return */
xfree (qop); /* force freeing mem and continue */
}
else if (algorithm != NULL && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
else if (algorithm && strcmp (algorithm,"MD5") && strcmp (algorithm,"MD5-sess"))
{
logprintf (LOG_NOTQUIET, _("Unsupported algorithm '%s'.\n"), algorithm);
xfree (qop); /* force freeing mem and return */
xfree (algorithm); /* force freeing mem and continue */
}
if (!realm || !nonce || !user || !passwd || !path || !method)
{
*auth_err = ATTRMISSING;
xfree (realm);
xfree (opaque);
xfree (nonce);
xfree (qop);
xfree (algorithm);
return NULL;
}
goto cleanup;
}
/* Calculate the digest value. */
{
@@ -4665,7 +4859,8 @@ digest_authentication_encode (const char *au, const char *user,
if (algorithm && !strcmp (algorithm, "MD5-sess"))
{
/* A1BUF = H( H(user ":" realm ":" password) ":" nonce ":" cnonce ) */
snprintf (cnonce, sizeof (cnonce), "%08x", random_number(INT_MAX));
snprintf (cnonce, sizeof (cnonce), "%08x",
(unsigned) random_number (INT_MAX));
md5_init_ctx (&ctx);
/* md5_process_bytes (hash, MD5_DIGEST_SIZE, &ctx); */
@@ -4687,12 +4882,13 @@ digest_authentication_encode (const char *au, const char *user,
md5_finish_ctx (&ctx, hash);
dump_hash (a2buf, hash);
if (qop && !strcmp(qop, "auth"))
if (qop && !strcmp (qop, "auth"))
{
/* RFC 2617 Digest Access Authentication */
/* generate random hex string */
if (!*cnonce)
snprintf(cnonce, sizeof(cnonce), "%08x", random_number(INT_MAX));
snprintf (cnonce, sizeof (cnonce), "%08x",
(unsigned) random_number (INT_MAX));
/* RESPONSE_DIGEST = H(A1BUF ":" nonce ":" noncecount ":" clientnonce ":" qop ": " A2BUF) */
md5_init_ctx (&ctx);
@@ -4702,9 +4898,9 @@ digest_authentication_encode (const char *au, const char *user,
md5_process_bytes ((unsigned char *)":", 1, &ctx);
md5_process_bytes ((unsigned char *)"00000001", 8, &ctx); /* TODO: keep track of server nonce values */
md5_process_bytes ((unsigned char *)":", 1, &ctx);
md5_process_bytes ((unsigned char *)cnonce, strlen(cnonce), &ctx);
md5_process_bytes ((unsigned char *)cnonce, strlen (cnonce), &ctx);
md5_process_bytes ((unsigned char *)":", 1, &ctx);
md5_process_bytes ((unsigned char *)qop, strlen(qop), &ctx);
md5_process_bytes ((unsigned char *)qop, strlen (qop), &ctx);
md5_process_bytes ((unsigned char *)":", 1, &ctx);
md5_process_bytes ((unsigned char *)a2buf, MD5_DIGEST_SIZE * 2, &ctx);
md5_finish_ctx (&ctx, hash);
@@ -4754,15 +4950,16 @@ digest_authentication_encode (const char *au, const char *user,
if (opaque)
{
res_len += snprintf(res + res_len, res_size - res_len, ", opaque=\"%s\"", opaque);
res_len += snprintf (res + res_len, res_size - res_len, ", opaque=\"%s\"", opaque);
}
if (algorithm)
{
snprintf(res + res_len, res_size - res_len, ", algorithm=\"%s\"", algorithm);
snprintf (res + res_len, res_size - res_len, ", algorithm=\"%s\"", algorithm);
}
}
cleanup:
xfree (realm);
xfree (opaque);
xfree (nonce);
@@ -4908,7 +5105,7 @@ ensure_extension (struct http_stat *hs, const char *ext, int *dt)
#ifdef TESTING
const char *
test_parse_range_header(void)
test_parse_range_header (void)
{
unsigned i;
static const struct {
@@ -4926,8 +5123,10 @@ test_parse_range_header(void)
{ "bytes 1-999/1000", 1, 999, 1000, true },
{ "bytes 42-1233/1234", 42, 1233, 1234, true },
{ "bytes 42-1233/*", 42, 1233, -1, true },
{ "bytes 0-2147483648/2147483649", 0, 2147483648, 2147483649, true },
{ "bytes 2147483648-4294967296/4294967297", 2147483648, 4294967296, 4294967297, true }
{ "bytes 0-2147483648/2147483649", 0, 2147483648U, 2147483649U, true },
#if SIZEOF_WGINT >= 8
{ "bytes 2147483648-4294967296/4294967297", 2147483648U, 4294967296ULL, 4294967297ULL, true },
#endif
};
wgint firstbyteptr[sizeof(wgint)];
@@ -4953,7 +5152,7 @@ test_parse_range_header(void)
}
const char *
test_parse_content_disposition(void)
test_parse_content_disposition (void)
{
unsigned i;
static const struct {
@@ -4975,7 +5174,7 @@ test_parse_content_disposition(void)
filename*1=\"B\"", "AA.ext", true },
};
for (i = 0; i < countof(test_array); ++i)
for (i = 0; i < countof (test_array); ++i)
{
char *filename;
bool res;

View File

@@ -35,7 +35,7 @@ as that of the covered work. */
struct url;
uerr_t http_loop (struct url *, struct url *, char **, char **, const char *,
uerr_t http_loop (const struct url *, struct url *, char **, char **, const char *,
int *, struct url *, struct iri *);
void save_cookies (void);
void http_cleanup (void);

View File

@@ -97,6 +97,8 @@ CMD_DECLARE (cmd_directory);
CMD_DECLARE (cmd_time);
CMD_DECLARE (cmd_vector);
CMD_DECLARE (cmd_use_askpass);
CMD_DECLARE (cmd_spec_dirstruct);
CMD_DECLARE (cmd_spec_header);
CMD_DECLARE (cmd_spec_warc_header);
@@ -115,6 +117,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 +145,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,7 +158,7 @@ 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 },
@@ -172,6 +178,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 },
@@ -203,7 +212,7 @@ static const struct {
{ "header", NULL, cmd_spec_header },
#ifdef HAVE_HSTS
{ "hsts", &opt.hsts, cmd_boolean },
{ "hsts-file", &opt.hsts_file, cmd_file },
{ "hstsfile", &opt.hsts_file, cmd_file },
#endif
{ "htmlextension", &opt.adjust_extension, cmd_boolean }, /* deprecated */
{ "htmlify", NULL, cmd_spec_htmlify },
@@ -216,7 +225,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 },
{ "ifmodifiedsince", &opt.if_modified_since, cmd_boolean },
{ "ignorecase", &opt.ignore_case, cmd_boolean },
{ "ignorelength", &opt.ignore_length, cmd_boolean },
{ "ignoretags", &opt.ignore_tags, cmd_vector },
@@ -227,9 +236,10 @@ static const struct {
#endif
{ "input", &opt.input_filename, cmd_file },
#ifdef HAVE_METALINK
{ "input-metalink", &opt.input_metalink, cmd_file },
{ "inputmetalink", &opt.input_metalink, cmd_file },
#endif
{ "iri", &opt.enable_iri, cmd_boolean },
{ "keepbadhash", &opt.keep_badhash, cmd_boolean },
{ "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
{ "limitrate", &opt.limit_rate, cmd_bytes },
{ "loadcookies", &opt.cookies_input, cmd_file },
@@ -238,7 +248,8 @@ static const struct {
{ "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 },
{ "metalinkindex", &opt.metalink_index, cmd_number_inf },
{ "metalinkoverhttp", &opt.metalink_over_http, cmd_boolean },
#endif
{ "method", &opt.method, cmd_string_uppercase },
{ "mirror", NULL, cmd_spec_mirror },
@@ -253,11 +264,14 @@ 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 },
{ "preferredlocation", &opt.preferred_location, cmd_string },
#endif
{ "preservepermissions", &opt.preserve_perm, cmd_boolean },
#ifdef HAVE_SSL
@@ -308,6 +322,7 @@ static const struct {
{ "tries", &opt.ntry, cmd_number_inf },
{ "trustservernames", &opt.trustservernames, cmd_boolean },
{ "unlink", &opt.unlink, cmd_boolean },
{ "useaskpass" , &opt.use_askpass, cmd_use_askpass },
{ "useproxy", &opt.use_proxy, cmd_boolean },
{ "user", &opt.user, cmd_string },
{ "useragent", NULL, cmd_spec_useragent },
@@ -329,6 +344,9 @@ static const struct {
#ifdef USE_WATT32
{ "wdebug", &opt.wdebug, cmd_boolean },
#endif
#ifdef ENABLE_XATTR
{ "xattr", &opt.enable_xattr, cmd_boolean },
#endif
};
/* Look up CMDNAME in the commands[] and return its position in the
@@ -368,6 +386,10 @@ defaults (void)
bit pattern will be the least of the implementors' worries. */
xzero (opt);
#ifdef HAVE_METALINK
opt.metalink_index = -1;
#endif
opt.cookies = true;
opt.verbose = -1;
opt.ntry = 20;
@@ -415,7 +437,7 @@ 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;
@@ -472,6 +494,12 @@ defaults (void)
/* HSTS is enabled by default */
opt.hsts = true;
#endif
#ifdef ENABLE_XATTR
opt.enable_xattr = true;
#else
opt.enable_xattr = false;
#endif
}
/* Return the user's home directory (strdup-ed), or NULL if none is
@@ -849,6 +877,10 @@ static bool
setval_internal (int comind, const char *com, const char *val)
{
assert (0 <= comind && ((size_t) comind) < countof (commands));
if ((unsigned) comind >= countof (commands))
return NULL;
DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
return commands[comind].action (com, val, commands[comind].place);
}
@@ -955,6 +987,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
@@ -962,24 +1006,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
@@ -1311,6 +1393,32 @@ cmd_time (const char *com, const char *val, void *place)
return true;
}
static bool
cmd_use_askpass (const char *com _GL_UNUSED, const char *val, void *place)
{
const char *env_name = "WGET_ASKPASS";
const char *env;
if (val && *val)
return cmd_string (com, val, place);
env = getenv (env_name);
if (!(env && *env))
{
env_name = "SSH_ASKPASS";
env = getenv (env_name);
}
if (!(env && *env))
{
fprintf (stderr, _("use-askpass requires a string or either environment variable WGET_ASKPASS or SSH_ASKPASS to be set.\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
return cmd_string (com, env, place);
}
#ifdef HAVE_SSL
static bool
cmd_cert_type (const char *com, const char *val, void *place)
@@ -1870,6 +1978,19 @@ cleanup (void)
xfree (opt.body_data);
xfree (opt.body_file);
xfree (opt.rejected_log);
xfree (opt.use_askpass);
#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 */
}

140
src/iri.c
View File

@@ -33,11 +33,14 @@ as that of the covered work. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iconv.h>
#include <stringprep.h>
#include <idna.h>
#include <idn-free.h>
#include <langinfo.h>
#include <errno.h>
#ifdef HAVE_ICONV
# include <iconv.h>
#endif
#include <idn2.h>
#include <unicase.h>
#include <unistr.h>
#include "utils.h"
#include "url.h"
@@ -45,9 +48,6 @@ as that of the covered work. */
#include "c-strcasestr.h"
#include "xstrndup.h"
/* RFC3987 section 3.1 mandates STD3 ASCII RULES */
#define IDNA_FLAGS IDNA_USE_STD3_ASCII_RULES
/* Note: locale encoding is kept in options struct (opt.locale) */
/* Given a string containing "charset=XXX", return the encoding if found,
@@ -88,10 +88,15 @@ parse_charset (const char *str)
}
/* Find the locale used, or fall back on a default value */
char *
const char *
find_locale (void)
{
return (char *) stringprep_locale_charset ();
const char *encoding = nl_langinfo(CODESET);
if (!encoding || !*encoding)
return "ASCII";
return encoding;
}
/* Basic check of an encoding name. */
@@ -129,8 +134,8 @@ do_conversion (const char *tocode, const char *fromcode, char const *in_org, siz
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;
}
@@ -146,7 +151,8 @@ do_conversion (const char *tocode, const char *fromcode, char const *in_org, siz
for (;;)
{
if (iconv (cd, &in, &inlen, out, &outlen) != (size_t)(-1))
if (iconv (cd, (ICONV_CONST char **) &in, &inlen, out, &outlen) != (size_t)(-1) &&
iconv (cd, NULL, NULL, out, &outlen) != (size_t)(-1))
{
*out = s;
*(s + len - outlen - done) = '\0';
@@ -158,7 +164,7 @@ do_conversion (const char *tocode, const char *fromcode, char const *in_org, siz
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__);
debug_logprintf ("logging suppressed, strings may contain password\n");
}
return true;
}
@@ -179,16 +185,10 @@ do_conversion (const char *tocode, const char *fromcode, char const *in_org, siz
}
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 */
@@ -206,7 +206,7 @@ do_conversion (const char *tocode, const char *fromcode, char const *in_org, siz
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__);
debug_logprintf ("logging suppressed, strings may contain password\n");
}
return false;
}
@@ -235,50 +235,6 @@ locale_to_utf8 (const char *str)
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 *
@@ -287,34 +243,50 @@ idn_encode (const struct iri *i, const char *host)
int ret;
char *ascii_encoded;
char *utf8_encoded = NULL;
const char *src;
#if IDN2_VERSION_NUMBER < 0x00140000
uint8_t *lower;
size_t len = 0;
#endif
/* Encode to UTF-8 if not done */
if (!i->utf8_encode)
{
if (!remote_to_utf8 (i, host, &utf8_encoded))
return NULL; /* Nothing to encode or an error occured */
src = utf8_encoded;
}
else
src = host;
if (!_utf8_is_valid(utf8_encoded ? utf8_encoded : host))
#if IDN2_VERSION_NUMBER >= 0x00140000
/* IDN2_TRANSITIONAL implies input NFC encoding */
if ((ret = idn2_lookup_u8 ((uint8_t *) src, (uint8_t **) &ascii_encoded, IDN2_NONTRANSITIONAL)) != IDN2_OK)
{
logprintf (LOG_VERBOSE, _("Invalid UTF-8 sequence: %s\n"),
quote(utf8_encoded ? utf8_encoded : host));
logprintf (LOG_VERBOSE, _("idn_encode failed (%d): %s\n"), ret,
quote (idn2_strerror (ret)));
}
#else
/* we need a conversion to lowercase */
lower = u8_tolower ((uint8_t *) src, u8_strlen ((uint8_t *) src) + 1, 0, UNINORM_NFKC, NULL, &len);
if (!lower)
{
logprintf (LOG_VERBOSE, _("Failed to convert to lower: %d: %s\n"),
errno, quote (src));
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)
if ((ret = idn2_lookup_u8 (lower, (uint8_t **) &ascii_encoded, IDN2_NFC_INPUT)) != IDN2_OK)
{
logprintf (LOG_VERBOSE, _("idn_encode failed (%d): %s\n"), ret,
quote (idna_strerror (ret)));
return NULL;
quote (idn2_strerror (ret)));
}
return ascii_encoded;
xfree (lower);
#endif
return ret == IDN2_OK ? ascii_encoded : NULL;
}
/* Try to decode an "ASCII encoded" host. Return the new domain in the locale
@@ -322,18 +294,24 @@ idn_encode (const struct iri *i, const char *host)
char *
idn_decode (const char *host)
{
/*
char *new;
int ret;
ret = idna_to_unicode_8zlz (host, &new, IDNA_FLAGS);
if (ret != IDNA_SUCCESS)
ret = idn2_register_u8 (NULL, host, (uint8_t **) &new, 0);
if (ret != IDN2_OK)
{
logprintf (LOG_VERBOSE, _("idn_decode failed (%d): %s\n"), ret,
quote (idna_strerror (ret)));
logprintf (LOG_VERBOSE, _("idn2_register_u8 failed (%d): %s: %s\n"), ret,
quote (idn2_strerror (ret)), host);
return NULL;
}
return new;
*/
/* idn2_register_u8() just works label by label.
* That is pretty much overhead for just displaying the original ulabels.
* To keep at least the debug output format, return a cloned host. */
return xstrdup(host);
}
/* Try to transcode string str from remote encoding to UTF-8. On success, *new

View File

@@ -40,11 +40,10 @@ struct iri {
#ifdef ENABLE_IRI
# include <idna.h>
# include <idn-free.h>
# include <idn2.h>
char *parse_charset (const char *str);
char *find_locale (void);
const char *find_locale (void);
bool check_encoding_name (const char *encoding);
const char *locale_to_utf8 (const char *str);
char *idn_encode (const struct iri *i, const char *host);
@@ -60,13 +59,13 @@ void set_content_encoding (struct iri *i, const char *charset);
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)
#define idn_encode(a,b) NULL
#define idn_decode(str) NULL
#define idn_free(str) ((void)0)
#define idn2_free(str) ((void)0)
#define remote_to_utf8(a,b,c) false
#define iri_new() (&dummy_iri)
#define iri_dup(a) (&dummy_iri)

138
src/log.c
View File

@@ -80,6 +80,18 @@ as that of the covered work. */
logging is inhibited, logfp is set back to NULL. */
static FILE *logfp;
/* Descriptor of the stdout|stderr */
static FILE *stdlogfp;
/* Descriptor of the wget.log* file (if created) */
static FILE *filelogfp;
/* Name of log file */
static char *logfile;
/* Is interactive shell ? */
static int shell_is_interactive;
/* A second file descriptor pointing to the temporary log file for the
WARC writer. If WARC writing is disabled, this is NULL. */
static FILE *warclogfp;
@@ -351,6 +363,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 +371,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 +390,8 @@ logputs (enum log_options o, const char *s)
logflush ();
else
needs_flushing = true;
errno = errno_save;
}
struct logvprintf_state {
@@ -543,8 +562,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 +582,8 @@ logprintf (enum log_options o, const char *fmt, ...)
exit (WGET_EXIT_GENERIC_ERROR);
}
while (!done);
errno = errno_saved;
}
#ifdef ENABLE_DEBUG
@@ -600,16 +623,18 @@ log_init (const char *file, bool appendp)
{
if (HYPHENP (file))
{
logfp = stdout;
stdlogfp = stdout;
logfp = stdlogfp;
}
else
{
logfp = fopen (file, appendp ? "a" : "w");
if (!logfp)
filelogfp = fopen (file, appendp ? "a" : "w");
if (!filelogfp)
{
fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
exit (WGET_EXIT_GENERIC_ERROR);
}
logfp = filelogfp;
}
}
else
@@ -620,7 +645,8 @@ log_init (const char *file, bool appendp)
stderr only if the user actually specifies `-O -'. He says
this inconsistency is harder to document, but is overall
easier on the user. */
logfp = stderr;
stdlogfp = stderr;
logfp = stdlogfp;
if (1
#ifdef HAVE_ISATTY
@@ -635,6 +661,11 @@ log_init (const char *file, bool appendp)
save_context_p = true;
}
}
#ifndef WINDOWS
/* Initialize this values so we don't have to ask every time we print line */
shell_is_interactive = isatty (STDIN_FILENO);
#endif
}
/* Close LOGFP (only if we opened it, not if it's stderr), inhibit
@@ -869,59 +900,78 @@ log_cleanup (void)
/* When SIGHUP or SIGUSR1 are received, the output is redirected
elsewhere. Such redirection is only allowed once. */
static enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
static const char *redirect_request_signal_name;
/* Redirect output to `wget-log'. */
/* Redirect output to `wget-log' or back to stdout/stderr. */
static void
redirect_output (void)
void
redirect_output (bool to_file, const char *signal_name)
{
char *logfile;
logfp = unique_create (DEFAULT_LOGFILE, false, &logfile);
if (logfp)
if (to_file && logfp != filelogfp)
{
fprintf (stderr, _("\n%s received, redirecting output to %s.\n"),
redirect_request_signal_name, quote (logfile));
xfree (logfile);
/* Dump the context output to the newly opened log. */
if (signal_name)
{
fprintf (stderr, "\n%s received.", signal_name);
}
if (!filelogfp)
{
filelogfp = unique_create (DEFAULT_LOGFILE, false, &logfile);
if (filelogfp)
{
fprintf (stderr, _("\nRedirecting output to %s.\n"),
quote (logfile));
/* Store signal name to tell wget it's permanent redirect to log file */
redirect_request_signal_name = signal_name;
logfp = filelogfp;
/* Dump the context output to the newly opened log. */
log_dump_context ();
}
else
{
/* Eek! Opening the alternate log file has failed. Nothing we
can do but disable printing completely. */
fprintf (stderr, _("%s: %s; disabling logging.\n"),
(logfile) ? logfile : DEFAULT_LOGFILE, strerror (errno));
inhibit_logging = true;
}
}
else
{
fprintf (stderr, _("\nRedirecting output to %s.\n"),
quote (logfile));
logfp = filelogfp;
log_dump_context ();
}
}
else if (!to_file && logfp != stdlogfp)
{
logfp = stdlogfp;
log_dump_context ();
}
else
{
/* Eek! Opening the alternate log file has failed. Nothing we
can do but disable printing completely. */
fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
fprintf (stderr, _("%s: %s; disabling logging.\n"),
(logfile) ? logfile : DEFAULT_LOGFILE, strerror (errno));
inhibit_logging = true;
}
save_context_p = false;
}
/* Check whether a signal handler requested the output to be
redirected. */
/* Check whether there's a need to redirect output. */
static void
check_redirect_output (void)
{
if (redirect_request == RR_REQUESTED)
#ifndef WINDOWS
/* If it was redirected already to log file by SIGHUP, SIGUSR1 or -o parameter,
* it was permanent.
* If there was no SIGHUP or SIGUSR1 and shell is interactive
* we check if process is fg or bg before every line is printed.*/
if (!redirect_request_signal_name && shell_is_interactive && !opt.lfilename)
{
redirect_request = RR_DONE;
redirect_output ();
if (tcgetpgrp (STDIN_FILENO) != getpgrp ())
{
/* Process backgrounded */
redirect_output (true,NULL);
}
else
{
/* Process foregrounded */
redirect_output (false,NULL);
}
}
}
/* Request redirection at a convenient time. This may be called from
a signal handler. */
void
log_request_redirect_output (const char *signal_name)
{
if (redirect_request == RR_NONE && save_context_p)
/* Request output redirection. The request will be processed by
check_redirect_output(), which is called from entry point log
functions. */
redirect_request = RR_REQUESTED;
redirect_request_signal_name = signal_name;
#endif /* WINDOWS */
}

View File

@@ -52,6 +52,7 @@ void log_init (const char *, bool);
void log_close (void);
void log_cleanup (void);
void log_request_redirect_output (const char *);
void redirect_output (bool, const char *);
const char *escnonprint (const char *);
const char *escnonprint_uri (const char *);

View File

@@ -36,6 +36,7 @@ as that of the covered work. */
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <spawn.h>
#ifdef ENABLE_NLS
# include <locale.h>
#endif
@@ -60,6 +61,7 @@ as that of the covered work. */
#include "version.h"
#include "c-strcase.h"
#include "dirname.h"
#include "xmemdup0.h"
#include <getopt.h>
#include <getpass.h>
#include <quote.h>
@@ -86,6 +88,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 */
@@ -123,7 +132,7 @@ redirect_output_signal (int sig)
signal_name = "SIGUSR1";
#endif
log_request_redirect_output (signal_name);
redirect_output (true,signal_name);
progress_schedule_redirect ();
signal (sig, redirect_output_signal);
}
@@ -197,10 +206,12 @@ save_hsts (void)
{
char *filename = get_hsts_database ();
if (filename)
DEBUGP (("Saving HSTS entries to %s\n", filename));
if (filename && hsts_store_has_changed (hsts_store))
{
DEBUGP (("Saving HSTS entries to %s\n", filename));
hsts_store_save (hsts_store, filename);
}
hsts_store_save (hsts_store, filename);
hsts_store_close (hsts_store);
xfree (filename);
@@ -210,8 +221,8 @@ save_hsts (void)
/* Definition of command-line options. */
static void _Noreturn print_help (void);
static void _Noreturn print_version (void);
_Noreturn static void print_help (void);
_Noreturn static void print_version (void);
#ifdef HAVE_SSL
# define IF_SSL(x) x
@@ -252,6 +263,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 },
@@ -277,6 +291,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 },
@@ -306,7 +323,7 @@ static struct cmdline_option option_data[] =
{ "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
#ifdef HAVE_HSTS
{ "hsts", 0, OPT_BOOLEAN, "hsts", -1},
{ "hsts-file", 0, OPT_VALUE, "hsts-file", -1 },
{ "hsts-file", 0, OPT_VALUE, "hstsfile", -1 },
#endif
{ "html-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 }, /* deprecated */
{ "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
@@ -325,9 +342,10 @@ static struct cmdline_option option_data[] =
#endif
{ "input-file", 'i', OPT_VALUE, "input", -1 },
#ifdef HAVE_METALINK
{ "input-metalink", 0, OPT_VALUE, "input-metalink", -1 },
{ "input-metalink", 0, OPT_VALUE, "inputmetalink", -1 },
#endif
{ "iri", 0, OPT_BOOLEAN, "iri", -1 },
{ "keep-badhash", 0, OPT_BOOLEAN, "keepbadhash", -1 },
{ "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
{ "level", 'l', OPT_VALUE, "reclevel", -1 },
{ "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
@@ -336,7 +354,8 @@ static struct cmdline_option option_data[] =
{ "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 },
{ "metalink-index", 0, OPT_VALUE, "metalinkindex", -1 },
{ "metalink-over-http", 0, OPT_BOOLEAN, "metalinkoverhttp", -1 },
#endif
{ "method", 0, OPT_VALUE, "method", -1 },
{ "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
@@ -350,11 +369,12 @@ 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 },
{ "preferred-location", 0, OPT_VALUE, "preferredlocation", -1 },
#endif
{ "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
{ IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
@@ -394,10 +414,11 @@ 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 },
{ "if-modified-since", 0, OPT_BOOLEAN, "ifmodifiedsince", -1 },
{ "tries", 't', OPT_VALUE, "tries", -1 },
{ "unlink", 0, OPT_BOOLEAN, "unlink", -1 },
{ "trust-server-names", 0, OPT_BOOLEAN, "trustservernames", -1 },
{ "use-askpass", 0, OPT_VALUE, "useaskpass", -1},
{ "use-server-timestamps", 0, OPT_BOOLEAN, "useservertimestamps", -1 },
{ "user", 0, OPT_VALUE, "user", -1 },
{ "user-agent", 'U', OPT_VALUE, "useragent", -1 },
@@ -419,6 +440,9 @@ static struct cmdline_option option_data[] =
{ "warc-tempdir", 0, OPT_VALUE, "warctempdir", -1 },
#ifdef USE_WATT32
{ "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
#endif
#ifdef ENABLE_XATTR
{ "xattr", 0, OPT_BOOLEAN, "xattr", -1 },
#endif
};
@@ -531,7 +555,7 @@ print_usage (int error)
/* Print the help message, describing all the available options. If
you add an option, be sure to update this list. */
static void _Noreturn
_Noreturn static void
print_help (void)
{
/* We split the help text this way to ease translation of individual
@@ -627,6 +651,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_("\
@@ -668,6 +698,11 @@ Download:\n"),
--password=PASS set both ftp and http password to PASS\n"),
N_("\
--ask-password prompt for passwords\n"),
N_("\
--use-askpass=COMMAND specify credential handler for requesting \n\
username and password. If no COMMAND is \n\
specified the WGET_ASKPASS or the SSH_ASKPASS \n\
environment variable is used.\n"),
N_("\
--no-iri turn off IRI support\n"),
N_("\
@@ -677,10 +712,18 @@ Download:\n"),
N_("\
--unlink remove file before clobber\n"),
#ifdef HAVE_METALINK
N_("\
--keep-badhash keep files with checksum mismatch (append .badhash)\n"),
N_("\
--metalink-index=NUMBER Metalink application/metalink4+xml metaurl ordinal NUMBER\n"),
N_("\
--metalink-over-http use Metalink metadata from HTTP response headers\n"),
N_("\
--preferred-location preferred location for Metalink resources\n"),
#endif
#ifdef ENABLE_XATTR
N_("\
--no-xattr turn off storage of metadata in extended file attributes\n"),
#endif
"\n",
@@ -784,6 +827,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 separated 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"),
@@ -992,6 +1040,103 @@ prompt_for_password (void)
return getpass("");
}
/* Execute external application opt.use_askpass */
static void
run_use_askpass (char *question, char **answer)
{
char tmp[1024];
pid_t pid;
int status;
int com[2];
ssize_t bytes = 0;
char *argv[3], *p;
posix_spawn_file_actions_t fa;
if (pipe (com) == -1)
{
fprintf (stderr, _("Cannot create pipe\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
status = posix_spawn_file_actions_init (&fa);
if (status)
{
fprintf (stderr,
_("Error initializing spawn file actions for use-askpass: %d\n"),
status);
exit (WGET_EXIT_GENERIC_ERROR);
}
status = posix_spawn_file_actions_adddup2 (&fa, com[1], STDOUT_FILENO);
if (status)
{
fprintf (stderr,
_("Error setting spawn file actions for use-askpass: %d\n"),
status);
exit (WGET_EXIT_GENERIC_ERROR);
}
/* C89 initializer lists must be computable at load time,
* thus this explicit initialization. */
argv[0] = opt.use_askpass;
argv[1] = question;
argv[2] = NULL;
status = posix_spawnp (&pid, opt.use_askpass, &fa, NULL, argv, environ);
if (status)
{
fprintf (stderr, "Error spawning %s: %d\n", opt.use_askpass, status);
exit (WGET_EXIT_GENERIC_ERROR);
}
/* Parent process reads from child. */
close (com[1]);
bytes = read (com[0], tmp, sizeof (tmp) - 1);
if (bytes <= 0)
{
fprintf (stderr,
_("Error reading response from command \"%s %s\": %s\n"),
opt.use_askpass, question, strerror (errno));
exit (WGET_EXIT_GENERIC_ERROR);
}
/* Make sure there is a trailing 0 */
tmp[bytes] = '\0';
/* Remove a possible new line */
if ((p = strpbrk (tmp, "\r\n")))
bytes = p - tmp;
*answer = xmemdup0 (tmp, bytes);
}
/* set the user name and password*/
static void
use_askpass (struct url *u)
{
static char question[1024];
if (u->user == NULL || u->user[0] == '\0')
{
snprintf (question, sizeof (question), _("Username for '%s%s': "),
scheme_leading_string(u->scheme), u->host);
/* Prompt for username */
run_use_askpass (question, &u->user);
if (opt.recursive)
opt.user = xstrdup (u->user);
}
if (u->passwd == NULL || u->passwd[0] == '\0')
{
snprintf(question, sizeof (question), _("Password for '%s%s@%s': "),
scheme_leading_string (u->scheme), u->user, u->host);
/* Prompt for password */
run_use_askpass (question, &u->passwd);
if (opt.recursive)
opt.passwd = xstrdup (u->passwd);
}
}
/* Function that prints the line argument while limiting it
to at most line_length. prefix is printed on the first line
and an appropriate number of spaces are added on subsequent
@@ -1053,7 +1198,7 @@ format_and_print_line (const char *prefix, const char *line,
return 0;
}
static void _Noreturn
_Noreturn static void
print_version (void)
{
const char *wgetrc_title = _("Wgetrc: ");
@@ -1312,7 +1457,8 @@ main (int argc, char **argv)
append_to_log = true;
break;
case OPT__EXECUTE:
run_command (optarg);
if (optarg) /* check silences static analyzer */
run_command (optarg);
break;
case OPT__NO:
{
@@ -1596,7 +1742,7 @@ for details.\n\n"));
else if (opt.method)
{
fprintf (stderr, _("You cannot use --post-data or --post-file along with --method. "
"--method expects data through --body-data and --body-file options"));
"--method expects data through --body-data and --body-file options\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
}
@@ -1675,6 +1821,16 @@ for details.\n\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
if (opt.use_askpass)
{
if (opt.use_askpass[0] == '\0')
{
fprintf (stderr,
_("use-askpass requires a string or either environment variable WGET_ASKPASS or SSH_ASKPASS to be set.\n"));
exit (WGET_EXIT_GENERIC_ERROR);
}
}
#ifdef USE_WATT32
if (opt.wdebug)
dbug_init();
@@ -1737,7 +1893,7 @@ for details.\n\n"));
}
else
{
struct_fstat st;
struct stat st;
#ifdef __VMS
/* Common fopen() optional arguments:
@@ -1774,6 +1930,58 @@ only if outputting to a regular file.\n"));
}
}
#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.
@@ -1841,14 +2049,26 @@ only if outputting to a regular file.\n"));
}
else
{
/* Request credentials if use_askpass is set. */
if (opt.use_askpass)
use_askpass (url_parsed);
if ((opt.recursive || opt.page_requisites)
&& ((url_scheme (*t) != SCHEME_FTP && url_scheme (*t) != SCHEME_FTPS)
&& ((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 || url_scheme (*t) == SCHEME_FTPS)
if (url_scheme (*t) == SCHEME_FTP
#ifdef HAVE_SSL
|| url_scheme (*t) == SCHEME_FTPS
#endif
)
opt.follow_ftp = 1;
retrieve_tree (url_parsed, NULL);

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,21 @@ as that of the covered work. */
uerr_t retrieve_from_metalink (const metalink_t *metalink);
int metalink_res_cmp (const void *res1, const void *res2);
int metalink_meta_cmp (const void* meta1, const void* meta2);
int metalink_check_safe_path (const char *path);
char *last_component (char const *name);
void replace_metalink_basename (char **name, char *ref);
char *get_metalink_basename (char *name);
void append_suffix_number (char **str, const char *sep, wgint num);
void clean_metalink_string (char **str);
void dequote_metalink_string (char **str);
void badhash_suffix (char *name);
void badhash_or_remove (char *name);
uerr_t fetch_metalink_file (const char *url_str,
bool resume, bool metalink_http,
const char *filename, char **destname);
bool find_key_value (const char *start,
const char *end,

View File

@@ -53,16 +53,13 @@ as that of the covered work. */
#endif
/* Defined in log.c. */
void log_request_redirect_output (const char *);
/* Windows version of xsleep in utils.c. */
void
xsleep (double seconds)
{
#if defined(HAVE_USLEEP) && defined(HAVE_SLEEP)
if (seconds > 1000)
if (seconds >= 1)
{
/* Explained in utils.c. */
sleep (seconds);
@@ -98,7 +95,7 @@ static void
ws_hangup (const char *reason)
{
fprintf (stderr, _("Continuing in background.\n"));
log_request_redirect_output (reason);
redirect_output (true, reason);
/* Detach process from the current console. Under Windows 9x, if we
were launched from a 16-bit process (which is usually the case;

View File

@@ -75,7 +75,7 @@ search_netrc (const char *host, const char **acc, const char **passwd,
#ifdef __VMS
int err;
struct_stat buf;
struct stat buf;
char *path = "SYS$LOGIN:.netrc";
netrc_list = NULL;
@@ -94,7 +94,7 @@ search_netrc (const char *host, const char **acc, const char **passwd,
if (home)
{
int err;
struct_stat buf;
struct stat buf;
char *path = (char *)alloca (strlen (home) + 1
+ strlen (NETRC_FILE_NAME) + 1);
sprintf (path, "%s/%s", home, NETRC_FILE_NAME);
@@ -439,7 +439,7 @@ free_netrc(acc_t *l)
int
main (int argc, char **argv)
{
struct_stat sb;
struct stat sb;
char *program_name, *file, *target;
acc_t *head, *a;

View File

@@ -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>
@@ -203,18 +204,20 @@ ssl_init (void)
#endif
SSL_library_init ();
SSL_load_error_strings ();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSLeay_add_all_algorithms ();
SSLeay_add_ssl_algorithms ();
#endif
switch (opt.secure_protocol)
{
#ifndef OPENSSL_NO_SSL2
#if !defined OPENSSL_NO_SSL2 && OPENSSL_VERSION_NUMBER < 0x10100000L
case secure_protocol_sslv2:
meth = SSLv2_client_method ();
break;
#endif
#ifndef OPENSSL_NO_SSL3
#ifndef OPENSSL_NO_SSL3_METHOD
case secure_protocol_sslv3:
meth = SSLv3_client_method ();
break;
@@ -506,6 +509,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
@@ -532,7 +551,12 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
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;
@@ -561,7 +585,7 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
DEBUGP (("SSL handshake timed out.\n"));
goto timeout;
}
if (scwt_ctx.result <= 0 || SSL_state(conn) != SSL_ST_OK)
if (scwt_ctx.result <= 0 || !SSL_is_init_finished(conn))
goto error;
ctx = xnew0 (struct openssl_transport_context);
@@ -650,6 +674,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
@@ -673,6 +756,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. */
@@ -682,6 +766,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)
{
@@ -758,9 +846,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;
@@ -795,7 +886,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)))
{
@@ -816,9 +907,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)
@@ -873,6 +966,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",
@@ -880,13 +980,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

@@ -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,
@@ -60,6 +67,7 @@ struct options
char *input_filename; /* Input filename */
#ifdef HAVE_METALINK
char *input_metalink; /* Input metalink file */
int metalink_index; /* Metalink application/metalink4+xml metaurl ordinal number. */
bool metalink_over_http; /* Use Metalink if present in HTTP response */
char *preferred_location; /* Preferred location for Metalink resources */
#endif
@@ -92,6 +100,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. */
@@ -115,9 +128,12 @@ struct options
bool warc_keep_log; /* Store the log file in a WARC record. */
char **warc_user_headers; /* User-defined WARC header(s). */
bool enable_xattr; /* Store metadata in POSIX extended attributes. */
char *user; /* Generic username */
char *passwd; /* Generic password */
bool ask_passwd; /* Ask for password? */
char *use_askpass; /* value to use for use-askpass if WGET_ASKPASS is not set */
bool always_rest; /* Always use REST. */
wgint start_pos; /* Start position of a download. */
@@ -215,7 +231,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 {
@@ -229,6 +245,11 @@ 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 separated 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 */
@@ -241,6 +262,7 @@ struct options
bool cookies; /* whether cookies are used. */
char *cookies_input; /* file we're loading the cookies from. */
char *cookies_output; /* file we're saving the cookies to. */
bool keep_badhash; /* Keep files with checksum mismatch. */
bool keep_session_cookies; /* whether session cookies should be
saved and loaded. */
@@ -289,7 +311,7 @@ struct options
bool enable_iri;
char *encoding_remote;
char *locale;
const char *locale;
bool trustservernames;
#ifdef __VMS

View File

@@ -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");
@@ -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)
@@ -891,11 +892,6 @@ get_eta (int *bcd)
p += sizeof (s) - 1; \
} while (0)
/* Use move_to_end (s) to get S to point the end of the string (the
terminating \0). This is faster than s+=strlen(s), but some people
are confused when they see strchr (s, '\0') in the code. */
#define move_to_end(s) s = strchr (s, '\0');
static void
create_image (struct bar_progress *bp, double dl_total_time, bool done)
{
@@ -903,11 +899,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 +924,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,23 +945,23 @@ 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) &&
@@ -992,9 +992,8 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
memcpy (p, bp->f_download + offset_bytes, bytes_in_filename);
p += bytes_in_filename;
padding = MAX_FILENAME_COLS - (padding + *cols_ret);
for (;padding;padding--)
*p++ = ' ';
*p++ = ' ';
memset (p, ' ', padding + 1);
p += padding + 1;
}
/* "xx% " */
@@ -1002,15 +1001,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)
@@ -1022,7 +1019,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);
@@ -1032,18 +1028,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)
@@ -1071,27 +1068,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)
@@ -1104,12 +1088,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)
{
@@ -1144,14 +1127,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
@@ -1161,21 +1144,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>
@@ -1184,8 +1171,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
@@ -1203,8 +1193,6 @@ display_image (char *buf)
static void
bar_set_params (char *params)
{
char *term = getenv ("TERM");
if (params)
{
char *param = strtok (params, ":");
@@ -1224,12 +1212,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

@@ -234,17 +234,19 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
FILE *rejectedlog = NULL; /* Don't write a rejected log. */
#define COPYSTR(x) (x) ? xstrdup(x) : NULL;
/* 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);
@@ -436,10 +438,15 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
struct url *url_parsed = url_parse (url, NULL, i, true);
struct iri *ci;
char *referer_url = url;
bool strip_auth = (url_parsed != NULL
&& url_parsed->user != NULL);
bool strip_auth;
assert (url_parsed != NULL);
if (!url_parsed)
continue;
strip_auth = (url_parsed && url_parsed->user);
/* Strip auth info if present */
if (strip_auth)
referer_url = url_string (url_parsed, URL_AUTH_HIDE);
@@ -449,9 +456,16 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
reject_reason r;
if (child->ignore_when_downloading)
continue;
{
DEBUGP (("Not following due to 'ignore' flag: %s\n", child->url->url));
continue;
}
if (dash_p_leaf_HTML && !child->link_inline_p)
continue;
{
DEBUGP (("Not following due to 'link inline' flag: %s\n", child->url->url));
continue;
}
r = download_child (child, url_parsed, depth,
start_url_parsed, blacklist, i);
@@ -610,7 +624,11 @@ download_child (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 || u->scheme == SCHEME_FTPS) && 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;
@@ -795,6 +813,12 @@ descend_redirect (const char *redirected, struct url *orig_parsed, int depth,
if (reason == WG_RR_SUCCESS)
blacklist_add (blacklist, upos->url->url);
else if (reason == WG_RR_LIST || reason == WG_RR_REGEX)
{
DEBUGP (("Ignoring decision for redirects, decided to load it.\n"));
blacklist_add (blacklist, upos->url->url);
reason = WG_RR_SUCCESS;
}
else
DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));

View File

@@ -634,7 +634,7 @@ retr_rate (wgint bytes, double secs)
double dlrate = calc_rate (bytes, secs, &units);
/* Use more digits for smaller numbers (regardless of unit used),
e.g. "1022", "247", "12.5", "2.38". */
sprintf (res, "%.*f %s",
snprintf (res, sizeof(res), "%.*f %s",
dlrate >= 99.95 ? 0 : dlrate >= 9.995 ? 1 : 2,
dlrate, !opt.report_bps ? rate_names[units]: rate_names_bits[units]);
@@ -830,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 || u->scheme == SCHEME_FTPS))
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;
@@ -864,15 +869,19 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
redirects, but a ton of boneheaded webservers and CGIs out
there break the rules and use relative URLs, and popular
browsers are lenient about this, so wget should be too. */
construced_newloc = uri_merge (url, mynewloc);
construced_newloc = uri_merge (url, mynewloc ? mynewloc : "");
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);
@@ -1060,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;
@@ -1099,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 && cur_url->url->scheme != SCHEME_FTPS) || 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 || cur_url->url->scheme == SCHEME_FTPS)
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,
@@ -1128,7 +1147,7 @@ retrieve_from_file (const char *file, bool html, int *count)
Removing file due to --delete-after in retrieve_from_file():\n"));
logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
if (unlink (filename))
logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
logprintf (LOG_NOTQUIET, "Failed to unlink %s: (%d) %s\n", filename, errno, strerror (errno));
dt &= ~RETROKF;
}
@@ -1229,9 +1248,9 @@ rotate_backups(const char *fname)
#endif
int maxlen = strlen (fname) + sizeof (SEP) + numdigit (opt.backups) + AVSL;
char *from = (char *)alloca (maxlen);
char *to = (char *)alloca (maxlen);
struct_stat sb;
char *from = alloca (maxlen);
char *to = alloca (maxlen);
struct stat sb;
int i;
if (stat (fname, &sb) == 0)
@@ -1248,17 +1267,21 @@ rotate_backups(const char *fname)
*/
if (i == opt.backups)
{
sprintf (to, "%s%s%d%s", fname, SEP, i, AVS);
snprintf (to, sizeof(to), "%s%s%d%s", fname, SEP, i, AVS);
delete (to);
}
#endif
sprintf (to, "%s%s%d", fname, SEP, i);
sprintf (from, "%s%s%d", fname, SEP, i - 1);
rename (from, to);
snprintf (to, maxlen, "%s%s%d", fname, SEP, i);
snprintf (from, maxlen, "%s%s%d", fname, SEP, i - 1);
if (rename (from, to))
logprintf (LOG_NOTQUIET, "Failed to rename %s to %s: (%d) %s\n",
from, to, errno, strerror (errno));
}
sprintf (to, "%s%s%d", fname, SEP, 1);
rename(fname, to);
snprintf (to, maxlen, "%s%s%d", fname, SEP, 1);
if (rename(fname, to))
logprintf (LOG_NOTQUIET, "Failed to rename %s to %s: (%d) %s\n",
fname, to, errno, strerror (errno));
}
static bool no_proxy_match (const char *, const char **);

View File

@@ -35,56 +35,11 @@ as that of the covered work. */
#ifndef SYSDEP_H
#define SYSDEP_H
/* Testing for __sun is not enough because it's also defined on SunOS. */
#ifdef __sun
# ifdef __SVR4
# define solaris
# endif
#endif
#if defined(__INTERIX) && !defined(_ALL_SOURCE)
# define _ALL_SOURCE
#endif
/* The "namespace tweaks" below attempt to set a friendly "compilation
environment" under popular operating systems. Default compilation
environment often means that some functions that are "extensions"
are not declared -- `strptime' is one example.
But non-default environments can expose bugs in the system header
files, crippling compilation in _very_ non-obvious ways. Because
of that, we define them only on well-tested architectures where we
know they will work. */
#undef NAMESPACE_TWEAKS
#ifdef solaris
# define NAMESPACE_TWEAKS
#endif
#if defined(__linux__) || defined(__GLIBC__)
# define NAMESPACE_TWEAKS
#endif
#ifdef NAMESPACE_TWEAKS
/* Request the "Unix 98 compilation environment". */
#define _XOPEN_SOURCE 500
#endif /* NAMESPACE_TWEAKS */
/* Alloca declaration, based on recommendation in the Autoconf manual.
These have to be after the above namespace tweaks, but before any
non-preprocessor code. */
/* Provided by gnulib on systems that don't have it: */
#include <alloca.h>
/* Must include these, so we can test for the missing stat macros and
define them as necessary. */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <inttypes.h>
@@ -98,108 +53,9 @@ as that of the covered work. */
# include "mswindows.h"
#endif
/* Provided by gnulib on systems that don't have it: */
# include <stdbool.h>
#ifndef struct_stat
# define struct_stat struct stat
#endif
#ifndef struct_fstat
# define struct_fstat struct stat
#endif
#include <intprops.h>
/* For CHAR_BIT, LONG_MAX, etc. */
#include <stdbool.h>
#include <limits.h>
#ifndef CHAR_BIT
# define CHAR_BIT 8
#endif
/* These are defined in cmpt.c if missing, so we must declare
them. */
#ifndef HAVE_STRCASECMP
int strcasecmp ();
#endif
#ifndef HAVE_STRNCASECMP
int strncasecmp ();
#endif
#ifndef HAVE_STRPTIME
char *strptime ();
#endif
#ifndef HAVE_TIMEGM
# include <time.h>
time_t timegm (struct tm *);
#endif
#ifndef HAVE_MEMRCHR
void *memrchr (const void *, int, size_t);
#endif
/* These are defined in snprintf.c. It would be nice to have an
snprintf.h, though. */
#ifndef HAVE_SNPRINTF
int snprintf (char *str, size_t count, const char *fmt, ...);
#endif
#ifndef HAVE_VSNPRINTF
#include <stdarg.h>
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. */
#ifdef HAVE_WORKING_FNMATCH_H
# define SYSTEM_FNMATCH
#endif
#include <fnmatch.h>
/* Provide sig_atomic_t if the system doesn't. */
#ifndef HAVE_SIG_ATOMIC_T
typedef int sig_atomic_t;
#endif
/* Provide uint32_t on the platforms that don't define it. Although
most code should be agnostic about integer sizes, some code really
does need a 32-bit integral type. Such code should use uint32_t.
(The exception is gnu-md5.[ch], which uses its own detection for
portability across platforms.) */
#ifndef HAVE_UINT32_T
# if SIZEOF_INT == 4
typedef unsigned int uint32_t;
# else
# if SIZEOF_LONG == 4
typedef unsigned long uint32_t;
# else
# if SIZEOF_SHORT == 4
typedef unsigned short uint32_t;
# else
#error "Cannot determine a 32-bit unsigned integer type"
# endif
# endif
# endif
#endif
/* If uintptr_t isn't defined, simply typedef it to unsigned long. */
#ifndef HAVE_UINTPTR_T
typedef unsigned long uintptr_t;
#endif
/* If intptr_t isn't defined, simply typedef it to long. */
#ifndef HAVE_INTPTR_T
typedef long intptr_t;
#endif
#include "intprops.h"
#endif /* SYSDEP_H */

107
src/url.c
View File

@@ -43,6 +43,11 @@ as that of the covered work. */
#include "host.h" /* for is_valid_ipv6_address */
#include "c-strcase.h"
#ifdef HAVE_ICONV
# include <iconv.h>
#endif
#include <langinfo.h>
#ifdef __VMS
#include "vms.h"
#endif /* def __VMS */
@@ -507,6 +512,12 @@ scheme_disable (enum url_scheme scheme)
supported_schemes[scheme].flags |= scm_disabled;
}
const char *
scheme_leading_string (enum url_scheme scheme)
{
return supported_schemes[scheme].leading_string;
}
/* Skip the username and password, if present in the URL. The
function should *not* be called with the complete URL, but with the
portion after the scheme.
@@ -1202,7 +1213,7 @@ url_free (struct url *url)
if (url)
{
if (url->idn_allocated) {
idn_free (url->host); /* A dummy if !defined(ENABLE_IRI) */
idn2_free (url->host); /* A dummy if !defined(ENABLE_IRI) */
url->host = NULL;
}
else
@@ -1231,7 +1242,7 @@ mkalldirs (const char *path)
{
const char *p;
char *t;
struct_stat st;
struct stat st;
int res;
p = path + strlen (path);
@@ -1266,12 +1277,14 @@ mkalldirs (const char *path)
name exists, we just remove it and create the directory
anyway. */
DEBUGP (("Removing %s because of directory danger!\n", t));
unlink (t);
if (unlink (t))
logprintf (LOG_NOTQUIET, "Failed to unlink %s (%d): %s\n",
t, errno, strerror(errno));
}
}
res = make_directory (t);
if (res != 0)
logprintf (LOG_NOTQUIET, "%s: %s", t, strerror (errno));
logprintf (LOG_NOTQUIET, "%s: %s\n", t, strerror (errno));
xfree (t);
return res;
}
@@ -1399,8 +1412,8 @@ UVWC, VC, VC, VC, VC, VC, VC, VC, /* NUL SOH STX ETX EOT ENQ ACK BEL */
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,
@@ -1531,6 +1544,80 @@ append_uri_pathel (const char *b, const char *e, bool escaped,
append_null (dest);
}
static char *
convert_fname (char *fname)
{
char *converted_fname = fname;
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, (ICONV_CONST char **) &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);
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".
@@ -1706,6 +1793,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.
@@ -1787,7 +1876,11 @@ path_simplify (enum url_scheme scheme, char *path)
for (--t; t > beg && t[-1] != '/'; t--)
;
}
else if (scheme == SCHEME_FTP || scheme == SCHEME_FTPS)
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

View File

@@ -100,8 +100,8 @@ struct url
char *user;
char *passwd;
/* 'host' is allocated by idna_to_ascii_8z() via idn_encode().
* Call 'idn_free()' to free this memory. */
/* 'host' is allocated by idn2_lookup_u8() via idn_encode().
* Call 'idn2_free()' to free this memory. */
bool idn_allocated;
};
@@ -124,6 +124,7 @@ bool url_has_scheme (const char *);
bool url_valid_scheme (const char *);
int scheme_default_port (enum url_scheme);
void scheme_disable (enum url_scheme);
const char *scheme_leading_string (enum url_scheme);
char *url_string (const struct url *, enum url_auth_mode);
char *url_file_name (const struct url *, char *);

View File

@@ -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"
@@ -103,7 +113,7 @@ as that of the covered work. */
#include "exits.h"
#include "c-strcase.h"
static void _Noreturn
_Noreturn static void
memfatal (const char *context, long attempted_size)
{
/* Make sure we don't try to store part of the log line, and thus
@@ -225,14 +235,20 @@ xstrdup_lower (const char *s)
/* Copy the string formed by two pointers (one on the beginning, other
on the char after the last char) to a new, malloc-ed location.
0-terminate it. */
0-terminate it.
If both pointers are NULL, the function returns an empty string. */
char *
strdupdelim (const char *beg, const char *end)
{
char *res = xmalloc (end - beg + 1);
memcpy (res, beg, end - beg);
res[end - beg] = '\0';
return res;
if (beg && beg <= end)
{
char *res = xmalloc (end - beg + 1);
memcpy (res, beg, end - beg);
res[end - beg] = '\0';
return res;
}
return xstrdup("");
}
/* Parse a string containing comma-separated elements, and return a
@@ -282,13 +298,6 @@ sepstring (const char *s)
vsnprintf until the correct size is found. Since Wget also ships a
fallback implementation of vsnprintf, this should be portable. */
/* Constant is using for limits memory allocation for text buffer.
Applicable in situation when: vasprintf is not available in the system
and vsnprintf return -1 when long line is truncated (in old versions of
glibc and in other system where C99 doesn`t support) */
#define FMT_MAX_LENGTH 1048576
char *
aprintf (const char *fmt, ...)
{
@@ -308,6 +317,13 @@ aprintf (const char *fmt, ...)
return str;
#else /* not HAVE_VASPRINTF */
/* Constant is using for limits memory allocation for text buffer.
Applicable in situation when: vasprintf is not available in the system
and vsnprintf return -1 when long line is truncated (in old versions of
glibc and in other system where C99 doesn`t support) */
#define FMT_MAX_LENGTH 1048576
/* vasprintf is unavailable. snprintf into a small buffer and
resize it as necessary. */
int size = 32;
@@ -557,7 +573,7 @@ int
remove_link (const char *file)
{
int err = 0;
struct_stat st;
struct stat st;
if (lstat (file, &st) == 0 && S_ISLNK (st.st_mode))
{
@@ -583,7 +599,7 @@ file_exists_p (const char *filename)
#ifdef HAVE_ACCESS
return access (filename, F_OK) >= 0;
#else
struct_stat buf;
struct stat buf;
return stat (filename, &buf) >= 0;
#endif
}
@@ -593,7 +609,7 @@ file_exists_p (const char *filename)
bool
file_non_directory_p (const char *path)
{
struct_stat buf;
struct stat buf;
/* Use lstat() rather than stat() so that symbolic links pointing to
directories can be identified correctly. */
if (lstat (path, &buf) != 0)
@@ -620,7 +636,7 @@ file_size (const char *filename)
fclose (fp);
return size;
#else
struct_stat st;
struct stat st;
if (stat (filename, &st) < 0)
return -1;
return st.st_size;
@@ -1174,7 +1190,7 @@ wget_read_file (const char *file)
#ifdef HAVE_MMAP
{
struct_fstat buf;
struct stat buf;
if (fstat (fd, &buf) < 0)
goto mmap_lose;
fm->length = buf.st_size;
@@ -1317,7 +1333,7 @@ merge_vecs (char **v1, char **v2)
for (j = 0; v2[j]; j++)
;
/* Reallocate v1. */
v1 = xrealloc (v1, (i + j + 1) * sizeof (char **));
v1 = xrealloc (v1, (i + j + 1) * sizeof (char *));
memcpy (v1 + i, v2, (j + 1) * sizeof (char *));
xfree (v2);
return v1;
@@ -1920,7 +1936,7 @@ random_float (void)
static sigjmp_buf run_with_timeout_env;
static void _Noreturn
_Noreturn static void
abort_run_with_timeout (int sig _GL_UNUSED)
{
assert (sig == SIGALRM);
@@ -2035,13 +2051,16 @@ run_with_timeout (double timeout, void (*fun) (void *), void *arg)
return false;
}
signal (SIGALRM, abort_run_with_timeout);
if (SETJMP (run_with_timeout_env) != 0)
{
/* Longjumped out of FUN with a timeout. */
signal (SIGALRM, SIG_DFL);
return true;
}
else
{
signal (SIGALRM, abort_run_with_timeout);
}
alarm_set (timeout);
fun (arg);
@@ -2130,7 +2149,7 @@ xsleep (double seconds)
base64 data. */
size_t
base64_encode (const void *data, size_t length, char *dest)
wget_base64_encode (const void *data, size_t length, char *dest)
{
/* Conversion table. */
static const char tbl[64] = {
@@ -2198,7 +2217,7 @@ base64_encode (const void *data, size_t length, char *dest)
This function originates from Free Recode. */
ssize_t
base64_decode (const char *base64, void *dest)
wget_base64_decode (const char *base64, void *dest)
{
/* Table of base64 values for first 128 characters. Note that this
assumes ASCII (but so does Wget in other places). */
@@ -2403,17 +2422,17 @@ mergesort_internal (void *base, void *temp, size_t size, size_t from, size_t to,
}
/* Stable sort with interface exactly like standard library's qsort.
Uses mergesort internally, allocating temporary storage with
alloca. */
Uses mergesort internally. */
void
stable_sort (void *base, size_t nmemb, size_t size,
int (*cmpfun) (const void *, const void *))
{
if (size > 1)
if (nmemb > 1 && size > 1)
{
void *temp = alloca (nmemb * size * sizeof (void *));
void *temp = xmalloc (nmemb * size);
mergesort_internal (base, temp, size, 0, nmemb - 1, cmpfun);
xfree(temp);
}
}
@@ -2514,13 +2533,212 @@ wg_hex_to_string (char *str_buffer, const char *hex_buffer, size_t hex_len)
for (i = 0; i < hex_len; i++)
{
/* Each byte takes 2 characters. */
sprintf (str_buffer + 2 * i, "%02x", hex_buffer[i] & 0xFF);
sprintf (str_buffer + 2 * i, "%02x", (unsigned) (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 = wget_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 = wget_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

@@ -37,6 +37,10 @@ as that of the covered work. */
/* 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
@@ -136,8 +140,8 @@ void xsleep (double);
/* How many bytes it will take to store LEN bytes in base64. */
#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
size_t base64_encode (const void *, size_t, char *);
ssize_t base64_decode (const char *, void *);
size_t wget_base64_encode (const void *, size_t, char *);
ssize_t wget_base64_decode (const char *, void *);
#ifdef HAVE_LIBPCRE
void *compile_pcre_regex (const char *);
@@ -161,4 +165,9 @@ 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

@@ -246,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,
@@ -1292,7 +1308,7 @@ warc_write_request_record (const char *url, const char *timestamp_str,
{
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);

View File

@@ -48,8 +48,10 @@ 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
@@ -359,7 +361,8 @@ typedef enum
TIMECONV_ERR,
METALINK_PARSE_ERROR, METALINK_RETR_ERROR,
METALINK_CHKSUM_ERROR, METALINK_SIG_ERROR, METALINK_MISSING_RESOURCE,
RETR_WITH_METALINK
RETR_WITH_METALINK,
METALINK_SIZE_ERROR
} uerr_t;
/* 2005-02-19 SMS.

79
src/xattr.c Normal file
View File

@@ -0,0 +1,79 @@
/* xattr.h -- POSIX Extended Attribute support.
Copyright (C) 2016 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include "wget.h"
#include <stdio.h>
#include <string.h>
#include "log.h"
#include "xattr.h"
#ifdef USE_XATTR
static int
write_xattr_metadata (const char *name, const char *value, FILE *fp)
{
int retval = -1;
if (name && value && fp)
{
retval = fsetxattr (fileno (fp), name, value, strlen (value), 0);
/* FreeBSD's extattr_set_fd returns the length of the extended attribute. */
retval = (retval < 0) ? retval : 0;
if (retval)
DEBUGP (("Failed to set xattr %s.\n", quote(name)));
}
return retval;
}
#else /* USE_XATTR */
static int
write_xattr_metadata (const char *name, const char *value, FILE *fp)
{
(void)name;
(void)value;
(void)fp;
return 0;
}
#endif /* USE_XATTR */
int
set_file_metadata (const char *origin_url, const char *referrer_url, FILE *fp)
{
/* Save metadata about where the file came from (requested, final URLs) to
* user POSIX Extended Attributes of retrieved file.
*
* For more details about the user namespace see
* [http://freedesktop.org/wiki/CommonExtendedAttributes] and
* [http://0pointer.de/lennart/projects/mod_mime_xattr/].
*/
int retval = -1;
if (!origin_url || !fp)
return retval;
retval = write_xattr_metadata ("user.xdg.origin.url", escnonprint_uri (origin_url), fp);
if ((!retval) && referrer_url)
retval = write_xattr_metadata ("user.xdg.referrer.url", escnonprint_uri (referrer_url), fp);
return retval;
}

45
src/xattr.h Normal file
View File

@@ -0,0 +1,45 @@
/* xattr.h -- POSIX Extended Attribute function mappings.
Copyright (C) 2016 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include <stdio.h>
#ifndef _XATTR_H
#define _XATTR_H
/* Store metadata name/value attributes against fp. */
int set_file_metadata (const char *origin_url, const char *referrer_url, FILE *fp);
#if defined(__linux)
/* libc on Linux has fsetxattr (5 arguments). */
# include <sys/xattr.h>
# define USE_XATTR
#elif defined(__APPLE__)
/* libc on OS/X has fsetxattr (6 arguments). */
# include <sys/xattr.h>
# define fsetxattr (file, name, buffer, size, flags) \
fsetxattr ((file), (name), (buffer), (size), 0, (flags))
# define USE_XATTR
#elif defined(__FreeBSD_version) && (__FreeBSD_version > 500000)
/* FreeBSD */
# include <sys/types.h>
# include <sys/extattr.h>
# define fsetxattr (file, name, buffer, size, flags) \
extattr_set_fd ((file), EXTATTR_NAMESPACE_USER, (name), (buffer), (size))
# define USE_XATTR
#endif
#endif /* _XATTR_H */

View File

@@ -27,8 +27,38 @@
if METALINK_IS_ENABLED
METALINK_TESTS = Test-metalink-xml.py \
Test-metalink-http.py
METALINK_TESTS = Test-metalink-http.py \
Test-metalink-http-quoted.py \
Test-metalink-http-baddigest.py \
Test-metalink-http-xml.py \
Test-metalink-http-xml-trust.py \
Test-metalink-http-xml-trust-name.py \
Test-metalink-http-xml-type.py \
Test-metalink-http-xml-type-trust.py \
Test-metalink-http-xml-type-content.py \
Test-metalink-http-xml-type-trust-content.py \
Test-metalink-xml.py \
Test-metalink-xml-continue.py \
Test-metalink-xml-relpath.py \
Test-metalink-xml-abspath.py \
Test-metalink-xml-homepath.py \
Test-metalink-xml-trust.py \
Test-metalink-xml-relpath-trust.py \
Test-metalink-xml-abspath-trust.py \
Test-metalink-xml-homepath-trust.py \
Test-metalink-xml-prefix.py \
Test-metalink-xml-relprefix.py \
Test-metalink-xml-absprefix.py \
Test-metalink-xml-homeprefix.py \
Test-metalink-xml-prefix-trust.py \
Test-metalink-xml-relprefix-trust.py \
Test-metalink-xml-absprefix-trust.py \
Test-metalink-xml-homeprefix-trust.py \
Test-metalink-xml-emptyprefix-trust.py \
Test-metalink-xml-size.py \
Test-metalink-xml-nohash.py \
Test-metalink-xml-nourls.py \
Test-metalink-xml-urlbreak.py
else
METALINK_TESTS =
endif
@@ -37,9 +67,13 @@ 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@";
SSL_TESTS = Test--https.py Test--https-crl.py
if WITH_SSL
AM_TESTS_ENVIRONMENT += export SSL_TESTS=1;
endif
if HAVE_PYTHON3
TESTS = Test-auth-basic-fail.py \
TESTS = Test-504.py \
Test-auth-basic-fail.py \
Test-auth-basic.py \
Test-auth-both.py \
Test-auth-digest.py \
@@ -48,6 +82,7 @@ if HAVE_PYTHON3
Test-auth-retcode.py \
Test-auth-with-content-disposition.py \
Test-c-full.py \
Test-condget.py \
Test-Content-disposition-2.py \
Test-Content-disposition.py \
Test--convert-links--content-on-error.py \
@@ -56,25 +91,28 @@ if HAVE_PYTHON3
Test-cookie-expires.py \
Test-cookie.py \
Test-Head.py \
Test-hsts.py \
Test--https.py \
Test--https-crl.py \
Test-hsts.py \
Test-missing-scheme-retval.py \
Test-O.py \
Test-pinnedpubkey-der-https.py \
Test-pinnedpubkey-der-no-check-https.py \
Test-pinnedpubkey-hash-https.py \
Test-pinnedpubkey-hash-no-check-fail-https.py \
Test-pinnedpubkey-pem-fail-https.py \
Test-pinnedpubkey-pem-https.py \
Test-Post.py \
Test-504.py \
Test--spider-r.py \
Test--rejected-log.py \
Test-recursive-basic.py \
Test-recursive-include.py \
Test-recursive-redirect.py \
Test-redirect.py \
Test-redirect-crash.py \
Test--rejected-log.py \
Test-reserved-chars.py \
Test-condget.py \
$(SSL_TESTS) \
Test--spider-r.py \
$(METALINK_TESTS)
# added test cases expected to fail here and under TESTS
if !WITH_SSL
XFAIL_TESTS = $(SSL_TESTS)
endif
endif
EXTRA_DIST = certs conf exc misc server test README $(TESTS)

View File

@@ -43,7 +43,8 @@ Working:
================================================================================
The Test Files are valid Python scripts and the default mask for them is 755.
A singular Test must be invoked in the following manner:
A singular Test must be invoked in the following manner, with the current
directory being the testenv directory:
$ ./python3 <Name of Test File> OR
$ ./<Name of Test File>
The script will then initialize the various elements and pass them to an object
@@ -97,6 +98,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:
@@ -116,7 +118,6 @@ from misc.wget_file import WgetFile
It is recommended that a small description of the Test Case is provided next.
This would be very helpful to future contributors.
Next, is the const variable, TEST_NAME that defines the name of the Test.
Each File in the Test must be represented as a WgetFile object. The WgetFile
Class has the following prototype:
@@ -129,14 +130,15 @@ The rules object is a dictionary element, with the key as the Rule Name and
value as the Rule Data. In most cases, the Rule Data is another dictionary.
Various variables used consistently across all tests are:
* WGET_OPTIONS: The command line string passed to Wget upon invokation. This
* WGET_OPTIONS: The command line string passed to Wget upon invocation. This
string may contain URLs, like in the case where in-URL authentication is
used. Variable names passed like {{var_name}} will be replaced by the
contents of the variable self.var_name before being passed to Wget
* WGET_URLS: This is a list of filenames which will be appended as the URLs
to Wget during invokation. This is a list of lists, where WGET_URLS[0]
to Wget during invocation. This is a list of lists, where WGET_URLS[0]
represents the list of Filenames called from Server[0], WGET_URLS[1] is a
list of files downloaded from Server[2], etc.
list of files downloaded from Server[2], etc. They must be relative URLs,
i.e., not start with "/".
* Files: This variable defines the files that exist in the Server's
filesystem. The Files variable is a list of lists of WgetFile objects.
This means that File[0] is a list of WgetFile objects that lie on Server[0],
@@ -153,13 +155,11 @@ Various variables used consistently across all tests are:
Both, the HTTPTest and FTPTest modules have the same prototype:
{
name,
pre_hook,
test_options,
post_hook,
protocols
}
name should be a string, and is usually passed to the TEST_NAME variable,
the three hooks should be Python dict objects and protocols should be a list of
protocols, like [HTTP, HTTPS].
@@ -214,7 +214,7 @@ executed. The currently supported options are:
download. The complete URL will be created and passed to Wget
automatically. (alias URLs)
* WgetCommands : A string consisting of the various commandline switches
sent to Wget upon invokation. Any data placed between {{ }} in this string
sent to Wget upon invocation. Any data placed between {{ }} in this string
will be replaced with the contents of self.<data> before being passed to
Wget. This is particularly useful for getting the hostname and port for a
file. While all Download URL's are passed to Urls, a notable exception is
@@ -280,13 +280,6 @@ red-flagged as a XPASS. Currently, tests expected to fail under valgrind are not
explicitly marked as XFAIL. Tests failing under valgrind must always be
considered a blocking error.
Remember to always name the Test correctly using the TEST_NAME variable. This
is essential since a directory with the Test Name is created and this can
cause synchronization problems when the Parallel Test Harness is used.
One can use the following command on Unix systems to check for TEST_NAME
clashes:
$ grep -r -h "TEST_NAME =" | cut -c13- | uniq -c -d
Work Remaining:
================================================================================

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
This test ensures that Wget link conversion works also on HTTP error pages.
"""
TEST_NAME = "Test--convert-links--content-on-error"
############# File Definitions ###############################################
a_x_FileContent = """
<!DOCTYPE html>
@@ -70,7 +69,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 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,

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
This test executed Wget in recursive mode with a rejected log outputted.
"""
TEST_NAME = "Rejected Log"
############# File Definitions ###############################################
mainpage = """
<html>
@@ -55,10 +54,10 @@ Disallow: /dummy.txt
"""
log = """\
REASON U_URL U_SCHEME U_HOST U_PORT U_PATH U_PARAMS U_QUERY U_FRAGMENT P_URL P_SCHEME P_HOST P_PORT P_PATH P_PARAMS P_QUERY P_FRAGMENT
BLACKLIST http%3A//127.0.0.1%3A{{port}}/index.html SCHEME_HTTP 127.0.0.1 {{port}} index.html http%3A//127.0.0.1%3A{{port}}/secondpage.html SCHEME_HTTP 127.0.0.1 {{port}} secondpage.html
ROBOTS http%3A//127.0.0.1%3A{{port}}/dummy.txt SCHEME_HTTP 127.0.0.1 {{port}} dummy.txt http%3A//127.0.0.1%3A{{port}}/thirdpage.html SCHEME_HTTP 127.0.0.1 {{port}} thirdpage.html
SPANNEDHOST http%3A//no.such.domain/ SCHEME_HTTP no.such.domain 80 http%3A//127.0.0.1%3A{{port}}/thirdpage.html SCHEME_HTTP 127.0.0.1 {{port}} thirdpage.html
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."
@@ -93,7 +92,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

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

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 a local file accordingly.
"""
TEST_NAME = "Content Disposition Header"
############# File Definitions ###############################################
File1 = """All that is gold does not glitter,
Not all those who wander are lost;
@@ -47,7 +46,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 correctly handles responses to HEAD requests
and does not actually download any data
"""
TEST_NAME = "HEAD Requests"
############# File Definitions ###############################################
File1 = "You shall not pass!"
@@ -35,7 +34,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 correctly handles the -O command for output
filenames.
"""
TEST_NAME = "Output Filename Command"
############# File Definitions ###############################################
File1 = "Test Contents."
@@ -36,7 +35,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,6 @@ from misc.wget_file import WgetFile
This is a Prototype Test File for multiple servers.
Ideally this File should be copied and edited to write new tests.
"""
TEST_NAME = "Parallel Prototype"
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File2 = "With lemon or cream?"
@@ -44,7 +43,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test,

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
Simple test for HTTP POST Requests usiong the --method command
"""
TEST_NAME = "HTTP POST Requests"
############# File Definitions ###############################################
File1 = """A reader lives a thousand lives before he dies, said Jojen.
The man who never reads lives only one"""
@@ -39,7 +38,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -1,14 +1,13 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.constants import HTTP, HTTPS
from test.base_test import HTTP, HTTPS
from misc.wget_file import WgetFile
"""
This is a Prototype Test File.
Ideally this File should be copied and edited to write new tests.
"""
TEST_NAME = "Prototype"
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File2 = "With lemon or cream?"
@@ -65,7 +64,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 returns the correct exit code when Basic
authentcation failes due to a username/password error.
"""
TEST_NAME = "Basic Authentication Failure"
############# File Definitions ###############################################
File1 = "I am an invisble man."
@@ -42,7 +41,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,6 @@ from misc.wget_file import WgetFile
Also, we ensure that Wget saves the host after a successfull auth and
doesn't wait for a challenge the second time.
"""
TEST_NAME = "Basic Authorization"
############# File Definitions ###############################################
File1 = "I am an invisble man."
File2 = "I too am an invisible man."
@@ -50,7 +49,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,6 @@ from misc.wget_file import WgetFile
Also, we ensure that Wget saves the host after a successfull auth and
doesn't wait for a challenge the second time.
"""
TEST_NAME = "Multiple authentication support"
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File2 = "With lemon or cream?"
@@ -78,7 +77,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
This test ensures Wget's Digest Authorization Negotiation.
"""
TEST_NAME = "Digest Authorization"
############# File Definitions ###############################################
File1 = "Need a cookie?"
File2 = "Want cookies with milk!"
@@ -57,7 +56,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 Wget's Basic Authorization Negotiation, when credentials
are provided in-URL
"""
TEST_NAME = "Auth no challenge in URL"
############# File Definitions ###############################################
File1 = "Need a cookie?"
@@ -45,7 +44,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 Wget's Basic Authorization Negotiation, when the
--auth-no-challenge command is used.
"""
TEST_NAME = "Auth No Challenge Command"
############# File Definitions ###############################################
File1 = "Need a cookie?"
@@ -45,7 +44,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,6 @@ from misc.wget_file import WgetFile
a 403 Forbidden by the Server.
"""
TEST_NAME = "Forbidden Retcode"
############# File Definitions ###############################################
File1 = "Apples and Oranges? Really?"
@@ -41,7 +40,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 handles Content-Disposition correctly when
coupled with Authentication
"""
TEST_NAME = "Authentication with Content Disposition"
############# File Definitions ###############################################
File1 = "Need a cookie?"
@@ -45,7 +44,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
Test Wget's response when the file requested already exists on disk with
a filesize greater than or equal to the requested file.
"""
TEST_NAME = "Test continue option"
############# File Definitions ###############################################
File1 = "abababababababababababababababababababababababababababababababababab"
File2 = "ababababababababababababababababababab"
@@ -44,7 +43,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
Simple test for HTTP Conditional-GET Requests using the -N command
"""
TEST_NAME = "HTTP Conditional-GET Requests"
############# File Definitions ###############################################
# Keep same length !
Cont1 = """THIS IS 1 FILE"""
@@ -131,7 +130,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 stores the cookie even in the event of a
401 Unauthorized Response
"""
TEST_NAME = "Basic Cookie 401 Response"
############# File Definitions ###############################################
File1 = """All happy families are alike;
Each unhappy family is unhappy in its own way"""
@@ -50,7 +49,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 identifies bad servers trying to set cookies
for a different domain and rejects them.
"""
TEST_NAME = "Cookie Domain Mismatch"
############# File Definitions ###############################################
File1 = "Would you care for a cup of coffee?"
File2 = "Anyone for chocochip cookies?"
@@ -49,7 +48,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,6 @@ from misc.wget_file import WgetFile
Simultaneuously, we also check if multiple cookies to the same domain
are handled correctly
"""
TEST_NAME = "Cookie Expires"
############# File Definitions ###############################################
File1 = "Hello World!"
File2 = "'Ello! This is Amazing!"
@@ -72,7 +71,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -6,7 +6,6 @@ from misc.wget_file import WgetFile
"""
This test ensures that Wget's cookie jar support works correctly.
"""
TEST_NAME = "Basic Cookie Functionality"
############# File Definitions ###############################################
File1 = """All happy families are alike;
Each unhappy family is unhappy in its own way"""
@@ -48,7 +47,6 @@ post_test = {
}
err = HTTPTest (
name=TEST_NAME,
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test

View File

@@ -9,6 +9,11 @@ import os
"""
This test makes sure Wget can parse a given HSTS database and apply the indicated HSTS policy.
"""
print (os.getenv('SSL_TESTS'))
if os.getenv('SSL_TESTS') is None:
exit (77)
def hsts_database_path():
hsts_file = ".wget-hsts-testenv"
return os.path.abspath(hsts_file)
@@ -25,8 +30,6 @@ def create_hsts_database(path, host, port):
f.write(host + "\t" + str(port) + "\t0\t" + str(curtime) + "\t" + max_age + "\n")
f.close()
TEST_NAME = "HSTS basic test"
File_Name = "hw"
File_Content = "Hello, world!"
File = WgetFile(File_Name, File_Content)
@@ -59,7 +62,6 @@ test_options = {
}
test = HTTPTest(
name = TEST_NAME,
pre_hook = pre_test,
post_hook = post_test,
test_params = test_options,

View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
import hashlib
from base64 import b64encode
"""
This is to test Metalink/HTTP with a malformed base64 Digest header.
With --trust-server-names, trust the metalink:file names.
Without --trust-server-names, don't trust the metalink:file names:
use the basename of --input-metalink, and add a sequential number
(e.g. .#1, .#2, etc.).
Strip the directory from unsafe paths.
"""
############# File Definitions ###############################################
bad = "Ouch!"
bad_sha256 = b64encode (hashlib.sha256 (bad.encode ('UTF-8')).digest ()).decode ('ascii')
LinkHeaders = ["<http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file>; rel=duplicate; pri=1"]
DigestHeader = "SHA-256=bad_base64,SHA-256={{BAD_HASH}}"
# This will be filled as soon as we know server hostname and port
MetaHTTPRules = {'SendHeader' : {}}
MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
wrong_file = WgetFile ("wrong_file", bad)
wrong_file_down = WgetFile ("main.metalink", bad)
WGET_OPTIONS = "--metalink-over-http"
WGET_URLS = [["main.metalink"]]
RequestList = [[
"HEAD /main.metalink",
"GET /wrong_file"
]]
Files = [[
MetaHTTP,
wrong_file
]]
Existing_Files = []
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [wrong_file_down]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : RequestList
}
http_test = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
)
http_test.server_setup()
### Get and use dynamic server sockname
srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
DigestHeader = DigestHeader.replace('{{BAD_HASH}}', bad_sha256)
# Helper function for hostname, port and digest substitution
def SubstituteServerInfo (text, host, port):
text = text.replace('{{SRV_HOST}}', host)
text = text.replace('{{SRV_PORT}}', str (port))
return text
MetaHTTPRules["SendHeader"] = {
'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
for LinkHeader in LinkHeaders ],
'Digest': DigestHeader
}
err = http_test.begin ()
exit (err)

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
import hashlib
from base64 import b64encode
"""
This is to test Metalink/HTTP quoted values support in Wget.
"""
# Helper function for hostname, port and digest substitution
def SubstituteServerInfo (text, host, port, digest):
text = text.replace('{{FILE1_HASH}}', digest)
text = text.replace('{{SRV_HOST}}', host)
text = text.replace('{{SRV_PORT}}', str (port))
return text
############# File Definitions ###############################################
File1 = "Would you like some Tea?"
File1_corrupted = "Would you like some Coffee?"
File1_lowPref = "Do not take this"
File1_sha256 = b64encode (hashlib.sha256 (File1.encode ('UTF-8')).digest ()).decode ('ascii')
Signature = '''-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.7 (GNU/Linux)
This is no valid signature. But it should be downloaded.
The attempt to verify should fail but should not prevent
a successful metalink resource retrieval (the sig failure
should not be fatal).
-----END PGP SIGNATURE-----
'''
File2 = "No meta data for this file."
LinkHeaders = [
# This file has low priority and should not be picked.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref>; rel=\"duplicate\"; pri=\"9\"; geo=\"pl\"",
# This file should be picked second, after hash failure.
"<http://0.0.0.0/File1_try2_badconnection>; rel =\"duplicate\";pref; pri=\"7\"",
# This signature download will fail.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig2.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
# Two good signatures
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
"<http://{{SRV_HOST}}:{{SRV_PORT}}/Sig.asc>; rel=\"describedby\"; type=\"application/pgp-signature\"",
# Bad URL scheme
"<invalid_url>; rel=\"duplicate\"; pri=\"4\"",
# rel missing
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; pri=\"1\"; pref",
# invalid rel
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1>; rel=\"strange\"; pri=\"4\"",
# This file should be picked first, because it has the lowest pri among preferred.
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try1_corrupted>; rel=\"duplicate\"; geo=\"su\"; pri=\"4\"; pref",
# This file should NOT be picked third due to preferred location set to 'uk'
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_badgeo>; rel =\"duplicate\";pri=\"5\"",
# This file should be picked as third try, and it should succeed
"<http://{{SRV_HOST}}:{{SRV_PORT}}/File1_try3_ok>; rel=\'duplicate\'; pri=\"5\";geo=\"uk\""
]
DigestHeader = "SHA-256=\'{{FILE1_HASH}}\'"
# This will be filled as soon as we know server hostname and port
MetaFileRules = {'SendHeader' : {}}
FileOkServer = WgetFile ("File1_try3_ok", File1)
FileBadPref = WgetFile ("File1_lowPref", File1_lowPref)
FileBadHash = WgetFile ("File1_try1_corrupted", File1_corrupted)
MetaFile = WgetFile ("test.meta", rules=MetaFileRules)
# In case of Metalink over HTTP, the local file name is
# derived from the URL suffix.
FileOkLocal = WgetFile ("test.meta", File1)
SigFile = WgetFile ("Sig.asc", Signature)
FileNoMeta = WgetFile ("File2", File2)
WGET_OPTIONS = "--metalink-over-http --preferred-location=uk"
WGET_URLS = [["test.meta", "File2"]]
Files = [[FileOkServer, FileBadPref, FileBadHash, MetaFile, SigFile, FileNoMeta]]
Existing_Files = []
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [FileNoMeta, FileOkLocal]
RequestList = [
[
"HEAD /test.meta",
"GET /Sig2.asc",
"GET /Sig.asc",
"GET /File1_try1_corrupted",
"GET /File1_try3_ok",
"HEAD /File2",
"GET /File2",
]
]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : RequestList,
}
http_test = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test,
)
http_test.server_setup()
srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
MetaFileRules["SendHeader"] = {
'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port, File1_sha256)
for LinkHeader in LinkHeaders ],
'Digest': SubstituteServerInfo (DigestHeader, srv_host, srv_port, File1_sha256),
}
err = http_test.begin ()
exit (err)

View File

@@ -0,0 +1,272 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
import hashlib
from base64 import b64encode
"""
This is to test Metalink/HTTP with Metalink/XML Link headers.
With --trust-server-names, trust the metalink:file names.
Without --trust-server-names, don't trust the metalink:file names:
use the basename of --input-metalink, and add a sequential number
(e.g. .#1, .#2, etc.).
Strip the directory from unsafe paths.
"""
############# File Definitions ###############################################
bad = "Ouch!"
bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
File1 = "Would you like some Tea?"
File1_lowPref = "Do not take this"
File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
File2 = "This is gonna be good"
File2_lowPref = "Not this one too"
File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
File3 = "A little more, please"
File3_lowPref = "That's just too much"
File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
File4 = "Maybe a biscuit?"
File4_lowPref = "No, thanks"
File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
File5 = "More Tea...?"
File5_lowPref = "I have to go..."
File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
MetaXml1 = \
"""<?xml version="1.0" encoding="utf-8"?>
<metalink version="3.0" xmlns="http://www.metalinker.org/">
<publisher>
<name>GNU Wget</name>
</publisher>
<license>
<name>GNU GPL</name>
<url>http://www.gnu.org/licenses/gpl.html</url>
</license>
<identity>Wget Test Files</identity>
<version>1.2.3</version>
<description>Wget Test Files description</description>
<files>
<file name="dir/File1">
<verification>
<hash type="sha256">{{FILE1_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
</resources>
</file>
<file name="dir/File2">
<verification>
<hash type="sha256">{{FILE2_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
</resources>
</file>
<file name="/dir/File3"> <!-- rejected by libmetalink -->
<verification>
<hash type="sha256">{{FILE3_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
</resources>
</file>
<file name="dir/File4">
<verification>
<hash type="sha256">{{FILE4_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
</resources>
</file>
<file name="dir/File5">
<verification>
<hash type="sha256">{{FILE5_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
</resources>
</file>
</files>
</metalink>
"""
MetaXml2 = \
"""<?xml version="1.0" encoding="utf-8"?>
<metalink version="3.0" xmlns="http://www.metalinker.org/">
<publisher>
<name>GNU Wget</name>
</publisher>
<license>
<name>GNU GPL</name>
<url>http://www.gnu.org/licenses/gpl.html</url>
</license>
<identity>Wget Test Files</identity>
<version>1.2.3</version>
<description>Wget Test Files description</description>
<files>
<file name="bad">
<verification>
<hash type="sha256">{{BAD_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
</resources>
</file>
</files>
</metalink>
"""
LinkHeaders = [
# This file has the lowest priority, and should go last
"<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"; name=\"newname.metalink\"",
# This file has the highest priority, and should go first
"<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
]
# This will be filled as soon as we know server hostname and port
MetaHTTPRules = {'SendHeader' : {}}
MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
wrong_file = WgetFile ("wrong_file", bad)
File1_orig = WgetFile ("File1", File1)
File1_down = WgetFile ("dir/File1", File1)
File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
File2_orig = WgetFile ("File2", File2)
File2_down = WgetFile ("dir/File2", File2)
File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
# rejected by libmetalink
File3_orig = WgetFile ("File3", File3)
File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
File4_orig = WgetFile ("File4", File4)
File4_down = WgetFile ("dir/File4", File4)
File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
File5_orig = WgetFile ("File5", File5)
File5_down = WgetFile ("dir/File5", File5)
File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
MetaFile1_down = WgetFile ("newname.metalink", MetaXml1)
MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=2"
WGET_URLS = [["main.metalink"]]
RequestList = [[
"HEAD /main.metalink",
"GET /404",
"GET /wrong_file",
"GET /test1.metalink",
"GET /File1",
"GET /File2",
"GET /File4",
"GET /File5"
]]
Files = [[
MetaHTTP,
wrong_file,
MetaFile1, MetaFile2,
File1_orig, File1_nono,
File2_orig, File2_nono,
File3_orig, File3_nono,
File4_orig, File4_nono,
File5_orig, File5_nono
]]
Existing_Files = []
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [
MetaFile1_down,
File1_down,
File2_down,
File4_down,
File5_down
]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : RequestList
}
http_test = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
)
http_test.server_setup()
### Get and use dynamic server sockname
srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
MetaFile1.content = MetaXml1
MetaFile1_down.content = MetaXml1
MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
MetaFile2.content = MetaXml2
# Helper function for hostname, port and digest substitution
def SubstituteServerInfo (text, host, port):
text = text.replace('{{SRV_HOST}}', host)
text = text.replace('{{SRV_PORT}}', str (port))
return text
MetaHTTPRules["SendHeader"] = {
'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
for LinkHeader in LinkHeaders ]
}
err = http_test.begin ()
exit (err)

View File

@@ -0,0 +1,272 @@
#!/usr/bin/env python3
from sys import exit
from test.http_test import HTTPTest
from misc.wget_file import WgetFile
import hashlib
from base64 import b64encode
"""
This is to test Metalink/HTTP with Metalink/XML Link headers.
With --trust-server-names, trust the metalink:file names.
Without --trust-server-names, don't trust the metalink:file names:
use the basename of --input-metalink, and add a sequential number
(e.g. .#1, .#2, etc.).
Strip the directory from unsafe paths.
"""
############# File Definitions ###############################################
bad = "Ouch!"
bad_sha256 = hashlib.sha256 (bad.encode ('UTF-8')).hexdigest ()
File1 = "Would you like some Tea?"
File1_lowPref = "Do not take this"
File1_sha256 = hashlib.sha256 (File1.encode ('UTF-8')).hexdigest ()
File2 = "This is gonna be good"
File2_lowPref = "Not this one too"
File2_sha256 = hashlib.sha256 (File2.encode ('UTF-8')).hexdigest ()
File3 = "A little more, please"
File3_lowPref = "That's just too much"
File3_sha256 = hashlib.sha256 (File3.encode ('UTF-8')).hexdigest ()
File4 = "Maybe a biscuit?"
File4_lowPref = "No, thanks"
File4_sha256 = hashlib.sha256 (File4.encode ('UTF-8')).hexdigest ()
File5 = "More Tea...?"
File5_lowPref = "I have to go..."
File5_sha256 = hashlib.sha256 (File5.encode ('UTF-8')).hexdigest ()
MetaXml1 = \
"""<?xml version="1.0" encoding="utf-8"?>
<metalink version="3.0" xmlns="http://www.metalinker.org/">
<publisher>
<name>GNU Wget</name>
</publisher>
<license>
<name>GNU GPL</name>
<url>http://www.gnu.org/licenses/gpl.html</url>
</license>
<identity>Wget Test Files</identity>
<version>1.2.3</version>
<description>Wget Test Files description</description>
<files>
<file name="dir/File1">
<verification>
<hash type="sha256">{{FILE1_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File1_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File1</url>
</resources>
</file>
<file name="dir/File2">
<verification>
<hash type="sha256">{{FILE2_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File2_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File2</url>
</resources>
</file>
<file name="/dir/File3"> <!-- rejected by libmetalink -->
<verification>
<hash type="sha256">{{FILE3_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File3_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File3</url>
</resources>
</file>
<file name="dir/File4">
<verification>
<hash type="sha256">{{FILE4_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File4_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File4</url>
</resources>
</file>
<file name="dir/File5">
<verification>
<hash type="sha256">{{FILE5_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="25">http://{{SRV_HOST}}:{{SRV_PORT}}/File5_lowPref</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/File5</url>
</resources>
</file>
</files>
</metalink>
"""
MetaXml2 = \
"""<?xml version="1.0" encoding="utf-8"?>
<metalink version="3.0" xmlns="http://www.metalinker.org/">
<publisher>
<name>GNU Wget</name>
</publisher>
<license>
<name>GNU GPL</name>
<url>http://www.gnu.org/licenses/gpl.html</url>
</license>
<identity>Wget Test Files</identity>
<version>1.2.3</version>
<description>Wget Test Files description</description>
<files>
<file name="bad">
<verification>
<hash type="sha256">{{BAD_HASH}}</hash>
</verification>
<resources>
<url type="http" preference="35">http://{{SRV_HOST}}:{{SRV_PORT}}/wrong_file</url>
<url type="http" preference="40">http://{{SRV_HOST}}:{{SRV_PORT}}/404</url>
<url type="http" preference="30">http://{{SRV_HOST}}:{{SRV_PORT}}/bad</url>
</resources>
</file>
</files>
</metalink>
"""
LinkHeaders = [
# This file has the lowest priority, and should go last
"<http://{{SRV_HOST}}:{{SRV_PORT}}/test1.metalink>; rel=describedby; pri=2; type=\"application/metalink4+xml\"",
# This file has the highest priority, and should go first
"<http://{{SRV_HOST}}:{{SRV_PORT}}/test2.metalink>; rel=describedby; pri=1; type=\"application/metalink4+xml\""
]
# This will be filled as soon as we know server hostname and port
MetaHTTPRules = {'SendHeader' : {}}
MetaHTTP = WgetFile ("main.metalink", rules=MetaHTTPRules)
wrong_file = WgetFile ("wrong_file", bad)
File1_orig = WgetFile ("File1", File1)
File1_down = WgetFile ("dir/File1", File1)
File1_nono = WgetFile ("File1_lowPref", File1_lowPref)
File2_orig = WgetFile ("File2", File2)
File2_down = WgetFile ("dir/File2", File2)
File2_nono = WgetFile ("File2_lowPref", File2_lowPref)
# rejected by libmetalink
File3_orig = WgetFile ("File3", File3)
File3_nono = WgetFile ("File3_lowPref", File3_lowPref)
File4_orig = WgetFile ("File4", File4)
File4_down = WgetFile ("dir/File4", File4)
File4_nono = WgetFile ("File4_lowPref", File4_lowPref)
File5_orig = WgetFile ("File5", File5)
File5_down = WgetFile ("dir/File5", File5)
File5_nono = WgetFile ("File5_lowPref", File5_lowPref)
MetaFile1 = WgetFile ("test1.metalink", MetaXml1)
MetaFile1_down = WgetFile ("test1.metalink", MetaXml1)
MetaFile2 = WgetFile ("test2.metalink", MetaXml2)
WGET_OPTIONS = "--trust-server-names --metalink-over-http --metalink-index=2"
WGET_URLS = [["main.metalink"]]
RequestList = [[
"HEAD /main.metalink",
"GET /404",
"GET /wrong_file",
"GET /test1.metalink",
"GET /File1",
"GET /File2",
"GET /File4",
"GET /File5"
]]
Files = [[
MetaHTTP,
wrong_file,
MetaFile1, MetaFile2,
File1_orig, File1_nono,
File2_orig, File2_nono,
File3_orig, File3_nono,
File4_orig, File4_nono,
File5_orig, File5_nono
]]
Existing_Files = []
ExpectedReturnCode = 0
ExpectedDownloadedFiles = [
MetaFile1_down,
File1_down,
File2_down,
File4_down,
File5_down
]
################ Pre and Post Test Hooks #####################################
pre_test = {
"ServerFiles" : Files,
"LocalFiles" : Existing_Files
}
test_options = {
"WgetCommands" : WGET_OPTIONS,
"Urls" : WGET_URLS
}
post_test = {
"ExpectedFiles" : ExpectedDownloadedFiles,
"ExpectedRetcode" : ExpectedReturnCode,
"FilesCrawled" : RequestList
}
http_test = HTTPTest (
pre_hook=pre_test,
test_params=test_options,
post_hook=post_test
)
http_test.server_setup()
### Get and use dynamic server sockname
srv_host, srv_port = http_test.servers[0].server_inst.socket.getsockname ()
MetaXml1 = MetaXml1.replace('{{FILE1_HASH}}', File1_sha256)
MetaXml1 = MetaXml1.replace('{{FILE2_HASH}}', File2_sha256)
MetaXml1 = MetaXml1.replace('{{FILE3_HASH}}', File3_sha256)
MetaXml1 = MetaXml1.replace('{{FILE4_HASH}}', File4_sha256)
MetaXml1 = MetaXml1.replace('{{FILE5_HASH}}', File5_sha256)
MetaXml1 = MetaXml1.replace('{{SRV_HOST}}', srv_host)
MetaXml1 = MetaXml1.replace('{{SRV_PORT}}', str (srv_port))
MetaFile1.content = MetaXml1
MetaFile1_down.content = MetaXml1
MetaXml2 = MetaXml2.replace('{{BAD_HASH}}', bad_sha256)
MetaXml2 = MetaXml2.replace('{{SRV_HOST}}', srv_host)
MetaXml2 = MetaXml2.replace('{{SRV_PORT}}', str (srv_port))
MetaFile2.content = MetaXml2
# Helper function for hostname, port and digest substitution
def SubstituteServerInfo (text, host, port):
text = text.replace('{{SRV_HOST}}', host)
text = text.replace('{{SRV_PORT}}', str (port))
return text
MetaHTTPRules["SendHeader"] = {
'Link': [ SubstituteServerInfo (LinkHeader, srv_host, srv_port)
for LinkHeader in LinkHeaders ]
}
err = http_test.begin ()
exit (err)

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