mirror of
https://github.com/mirror/wget.git
synced 2026-08-24 03:53:28 +08:00
Compare commits
340 Commits
v1.14
...
parallel-w
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af702340a1 | ||
|
|
f8e9a64ec7 | ||
|
|
5753ed4a72 | ||
|
|
03f8babefe | ||
|
|
3858500de4 | ||
|
|
e29020e10c | ||
|
|
be78cba9e5 | ||
|
|
6cb857502f | ||
|
|
65fc59aefa | ||
|
|
8b83306d54 | ||
|
|
b89cda0a77 | ||
|
|
0606f1a133 | ||
|
|
c443399ab1 | ||
|
|
7cbe8141d1 | ||
|
|
eab853b7e6 | ||
|
|
3d7797c46e | ||
|
|
6140b1b6e3 | ||
|
|
cae32d41c1 | ||
|
|
c22b806ee0 | ||
|
|
ca69294c8a | ||
|
|
a44841cbe2 | ||
|
|
87a5922141 | ||
|
|
e43ae39dff | ||
|
|
c5f2c7fcef | ||
|
|
550cd6e9d2 | ||
|
|
97ce41b2d0 | ||
|
|
416d0e892c | ||
|
|
e2c8436e17 | ||
|
|
ebda24eb69 | ||
|
|
582e5d8ef7 | ||
|
|
601401da71 | ||
|
|
99ccc492f4 | ||
|
|
f3289f76ec | ||
|
|
825716399c | ||
|
|
26787225c1 | ||
|
|
104fd20ac3 | ||
|
|
ca402e2f81 | ||
|
|
8445279306 | ||
|
|
bb025955c3 | ||
|
|
08cedb953b | ||
|
|
c03855be40 | ||
|
|
3e8f9a6436 | ||
|
|
5a712b5bcf | ||
|
|
964ba0a0d5 | ||
|
|
ffccc7d3be | ||
|
|
d1ab00cab4 | ||
|
|
dd1b69c600 | ||
|
|
3b502901c0 | ||
|
|
a22cd7394b | ||
|
|
8a83a9d893 | ||
|
|
8e6de1fb5f | ||
|
|
8a919932a6 | ||
|
|
087e17be1c | ||
|
|
ee5b28367c | ||
|
|
4d77b190fd | ||
|
|
21908a4b13 | ||
|
|
ecd69778bf | ||
|
|
d26c8ebb16 | ||
|
|
507383df07 | ||
|
|
195393bf41 | ||
|
|
42e482ad99 | ||
|
|
82f44f303a | ||
|
|
31e5f33b5e | ||
|
|
422171da81 | ||
|
|
854ebbf4dd | ||
|
|
8624553a31 | ||
|
|
4eeabffee6 | ||
|
|
f2b9004e8f | ||
|
|
38a7829dcb | ||
|
|
351e438e51 | ||
|
|
6d4158122c | ||
|
|
8c2fd06ba8 | ||
|
|
67a4c6cf97 | ||
|
|
848d7537e1 | ||
|
|
6c572cbc33 | ||
|
|
df96c81cf3 | ||
|
|
97787110a2 | ||
|
|
226785838a | ||
|
|
60a95d8393 | ||
|
|
320cfdcb65 | ||
|
|
d7ea21b2e7 | ||
|
|
c9bc854938 | ||
|
|
ed54c64ad2 | ||
|
|
701e407af5 | ||
|
|
dfa1f4e064 | ||
|
|
35ab8cdd7a | ||
|
|
43c89ab7a5 | ||
|
|
5bb2f43165 | ||
|
|
605eafa792 | ||
|
|
d68295bdb1 | ||
|
|
59080465d1 | ||
|
|
b65b9cb8c5 | ||
|
|
593b59c697 | ||
|
|
9020b71c18 | ||
|
|
b9e5c3e8b3 | ||
|
|
87186cbc2f | ||
|
|
f694b2ea24 | ||
|
|
d260ded060 | ||
|
|
b31e6e4674 | ||
|
|
b828a6e4a7 | ||
|
|
7effa90359 | ||
|
|
7e1f4c1abc | ||
|
|
f616192dfd | ||
|
|
31868fed6c | ||
|
|
70f7cdf1af | ||
|
|
351d328c07 | ||
|
|
3b6a3e84a0 | ||
|
|
fb23bc0611 | ||
|
|
cb358c0a84 | ||
|
|
59a03f15dd | ||
|
|
fa670282ee | ||
|
|
0d58672dc6 | ||
|
|
93597efe7b | ||
|
|
3010d9c281 | ||
|
|
12218d353b | ||
|
|
ebfae2c353 | ||
|
|
15d167e264 | ||
|
|
b87cee3763 | ||
|
|
1a48da4cdc | ||
|
|
3832728138 | ||
|
|
38933de17c | ||
|
|
aed7d4163a | ||
|
|
349cbd0dd5 | ||
|
|
42c15e47b4 | ||
|
|
c3835a425a | ||
|
|
8b2954e58a | ||
|
|
bba67890f3 | ||
|
|
0c9fb2b041 | ||
|
|
d9f1cd05c1 | ||
|
|
921a23d60c | ||
|
|
7d18fd1025 | ||
|
|
43ca403306 | ||
|
|
93ad38686a | ||
|
|
fbd9b9c16b | ||
|
|
1fd32c995c | ||
|
|
c289349684 | ||
|
|
1dec2028d0 | ||
|
|
89024dda4f | ||
|
|
00c93a0625 | ||
|
|
44c821227c | ||
|
|
cb5c287f02 | ||
|
|
3dfba0bec8 | ||
|
|
fd80f6e878 | ||
|
|
db4262d6dd | ||
|
|
7743384820 | ||
|
|
b703633715 | ||
|
|
0758f47954 | ||
|
|
43bb61b4e3 | ||
|
|
d4d0e6378c | ||
|
|
f5785003b1 | ||
|
|
8b1a9b6de7 | ||
|
|
7e85e9509e | ||
|
|
85dd2f7ce2 | ||
|
|
e84192a8d3 | ||
|
|
99659f3295 | ||
|
|
e1fc2057c7 | ||
|
|
cb94e52d0f | ||
|
|
886ac1a89b | ||
|
|
e74c2ec25e | ||
|
|
48644f174e | ||
|
|
b6f9efe7b5 | ||
|
|
4c9e6b4f71 | ||
|
|
e13bc90211 | ||
|
|
60d1f4d1ad | ||
|
|
738b299419 | ||
|
|
9b9d16b2f3 | ||
|
|
ae958db622 | ||
|
|
50b4f0c72b | ||
|
|
dccc154a0e | ||
|
|
eaf2fc9a4f | ||
|
|
e505664ef3 | ||
|
|
e6123ed645 | ||
|
|
5137cff125 | ||
|
|
42c78fdd71 | ||
|
|
a7df7ecc2f | ||
|
|
695f11304b | ||
|
|
a12bd59111 | ||
|
|
4445d48471 | ||
|
|
ffb94036f2 | ||
|
|
92035dbabd | ||
|
|
c19d76c024 | ||
|
|
a300f1e47d | ||
|
|
72b2c58983 | ||
|
|
c52bbad9e4 | ||
|
|
44ba49b31f | ||
|
|
eee1589ef3 | ||
|
|
e9cc8b2f7c | ||
|
|
b8f036d16c | ||
|
|
f29fded6f4 | ||
|
|
a528894d13 | ||
|
|
91f0f99e9a | ||
|
|
c78caecbb4 | ||
|
|
8760123cee | ||
|
|
c9c0e4c641 | ||
|
|
7bb672a487 | ||
|
|
747023c476 | ||
|
|
29cf6bb9d1 | ||
|
|
9e0d87a248 | ||
|
|
6a2d67b583 | ||
|
|
3595b9de52 | ||
|
|
2d1196b116 | ||
|
|
74d5c8bfb7 | ||
|
|
fec5bb9e93 | ||
|
|
49f6d0ded8 | ||
|
|
4df7703d62 | ||
|
|
7f43748544 | ||
|
|
9d35f87218 | ||
|
|
90896e3314 | ||
|
|
5ce9389384 | ||
|
|
5f48ec1500 | ||
|
|
8560182d57 | ||
|
|
8e5038747b | ||
|
|
82126ccb67 | ||
|
|
ced4c1de82 | ||
|
|
099d8ee3da | ||
|
|
e976d4f3dc | ||
|
|
ccd369d5f2 | ||
|
|
027d9f385d | ||
|
|
83837b0606 | ||
|
|
ae80fd2ec7 | ||
|
|
277785fa2a | ||
|
|
52dd6da6e0 | ||
|
|
550457bcad | ||
|
|
8dc52c6eaa | ||
|
|
54fd8de415 | ||
|
|
81409cb9c8 | ||
|
|
04fcd759fd | ||
|
|
e9058befae | ||
|
|
0e6f1c2dac | ||
|
|
7df4b05f0b | ||
|
|
bc2891f307 | ||
|
|
6c30653a1a | ||
|
|
edbeaa0c4e | ||
|
|
e3b3ea5120 | ||
|
|
50238e49b9 | ||
|
|
6443581d72 | ||
|
|
c1a44a16ef | ||
|
|
3be7e0a53c | ||
|
|
5a0f05423a | ||
|
|
3217905144 | ||
|
|
b56a528aea | ||
|
|
dcf667fb57 | ||
|
|
a2c0835007 | ||
|
|
e23e8101db | ||
|
|
2dd255596a | ||
|
|
979a485a9a | ||
|
|
617bb37d6e | ||
|
|
0717a886c2 | ||
|
|
2f2483214c | ||
|
|
e6d8e165c5 | ||
|
|
3ebbd84518 | ||
|
|
b60ff61b75 | ||
|
|
2c1e0326a3 | ||
|
|
359dd16760 | ||
|
|
1e229375aa | ||
|
|
4f09a3118f | ||
|
|
b1838bdfd1 | ||
|
|
98f843f3cc | ||
|
|
9e8d899a35 | ||
|
|
5dcb116087 | ||
|
|
7c8735a6ee | ||
|
|
242ddfc74e | ||
|
|
13c6e7832a | ||
|
|
22bd8011e8 | ||
|
|
fe401688a6 | ||
|
|
6e4c3ab999 | ||
|
|
022dbcb343 | ||
|
|
7c0270cdb5 | ||
|
|
67e6027ea1 | ||
|
|
e9845d2813 | ||
|
|
959e5d1e90 | ||
|
|
c24dce1d07 | ||
|
|
e7e869f951 | ||
|
|
bfe30ea754 | ||
|
|
74f6cb8884 | ||
|
|
e2cb2fa2e3 | ||
|
|
b718128b4f | ||
|
|
798f554773 | ||
|
|
06fc1edb54 | ||
|
|
85b98d0834 | ||
|
|
dcc6abee90 | ||
|
|
4759cf099f | ||
|
|
4cd6292b31 | ||
|
|
6b59fab021 | ||
|
|
1d18db4bac | ||
|
|
ed8335aa76 | ||
|
|
87a2b8dcb6 | ||
|
|
a41525e5c2 | ||
|
|
76790a386a | ||
|
|
c25d01feb7 | ||
|
|
f51826d9d8 | ||
|
|
721697aef6 | ||
|
|
270460da98 | ||
|
|
fa9aaf2ce6 | ||
|
|
eb01e9d442 | ||
|
|
2807c5c56d | ||
|
|
e37ea16957 | ||
|
|
5abb1dc188 | ||
|
|
54e5b5d373 | ||
|
|
768202bf88 | ||
|
|
5e2c6fefe4 | ||
|
|
0ea58b0c31 | ||
|
|
3d19087207 | ||
|
|
dc7e47d4d1 | ||
|
|
b1bc6efc8a | ||
|
|
d65343a57b | ||
|
|
68dbb9ead7 | ||
|
|
98db799759 | ||
|
|
8cfac52713 | ||
|
|
11d09dd001 | ||
|
|
159c371492 | ||
|
|
38b1df95f9 | ||
|
|
f07e0a67b4 | ||
|
|
47bd180ab0 | ||
|
|
198acf4844 | ||
|
|
5090e0c433 | ||
|
|
bb28bda88f | ||
|
|
9fd1e97e40 | ||
|
|
40493a76fe | ||
|
|
6f102902ad | ||
|
|
26ca40970a | ||
|
|
2f6ef8922b | ||
|
|
39aaaf57f8 | ||
|
|
5f4debb6f8 | ||
|
|
2b8e2f8879 | ||
|
|
b5a8d663f7 | ||
|
|
44f75a1955 | ||
|
|
f4c42b94d8 | ||
|
|
1e1054db8a | ||
|
|
5c608df4e1 | ||
|
|
8bc3dbf2d4 | ||
|
|
7ccf4210f6 | ||
|
|
8c66c94989 | ||
|
|
15bfd733f9 | ||
|
|
f63e2230d7 | ||
|
|
693b791082 | ||
|
|
02d225b5ca | ||
|
|
671d681304 | ||
|
|
6ceea0d064 | ||
|
|
fc220632fb |
91
.gitignore
vendored
Normal file
91
.gitignore
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
# Project Root
|
||||
/.sc-start-sc_bindtextdomain
|
||||
/.sc-start-sc_prohibit_HAVE_MBRTOWC
|
||||
/.version
|
||||
/GNUmakefile
|
||||
/INSTALL
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/config.cache
|
||||
/config.log
|
||||
/config.status
|
||||
/configure
|
||||
/lib/
|
||||
/maint.mk
|
||||
# Wildcard Ignores
|
||||
*~
|
||||
po/*.gmo*
|
||||
po/*.po*
|
||||
src/*.o
|
||||
testenv/*.log
|
||||
testenv/*.trs
|
||||
# build-aux/
|
||||
build-aux/.gitignore
|
||||
build-aux/compile
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
build-aux/depcomp
|
||||
build-aux/install-sh
|
||||
build-aux/mdate-sh
|
||||
build-aux/missing
|
||||
build-aux/snippet/
|
||||
build-aux/test-driver
|
||||
build-aux/texinfo.tex
|
||||
# doc/
|
||||
doc/Makefile
|
||||
doc/Makefile.in
|
||||
doc/sample.wgetrc.munged_for_texi_inclusion
|
||||
doc/stamp-vti
|
||||
doc/version.texi
|
||||
doc/wget.1
|
||||
doc/wget.info
|
||||
doc/wget.pod
|
||||
# m4/
|
||||
m4/.gitignore
|
||||
m4/gnulib-cache.m4
|
||||
# po/
|
||||
po/.gitignore
|
||||
po/.reference/
|
||||
po/LINGUAS
|
||||
po/Makefile
|
||||
po/Makefile.in
|
||||
po/Makevars
|
||||
po/POTFILES
|
||||
po/wget.pot
|
||||
# src/
|
||||
src/.deps/
|
||||
src/Makefile
|
||||
src/Makefile.in
|
||||
src/build_info.c
|
||||
src/config.h
|
||||
src/config.h.in
|
||||
src/cscope.out
|
||||
src/css.c
|
||||
src/css_.c
|
||||
src/libunittest.a
|
||||
src/stamp-h1
|
||||
src/tags
|
||||
src/version.c
|
||||
src/wget
|
||||
# testenv/
|
||||
testenv/conf/__pycache__/
|
||||
testenv/exc/__pycache__/
|
||||
testenv/misc/__pycache__/
|
||||
testenv/server/__pycache__/
|
||||
testenv/server/http/__pycache__/
|
||||
testenv/test/__pycache__/
|
||||
testenv/Makefile
|
||||
testenv/Makefile.in
|
||||
# tests/
|
||||
tests/Makefile
|
||||
tests/Makefile.in
|
||||
tests/WgetTest.pm
|
||||
tests/unit-tests
|
||||
# util/
|
||||
util/Makefile
|
||||
util/Makefile.in
|
||||
# others
|
||||
/tags
|
||||
/cscope.out
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "gnulib"]
|
||||
path = gnulib
|
||||
url = git://git.sv.gnu.org/gnulib.git
|
||||
@@ -1065,4 +1065,3 @@ developed inside the GNU project. Therefore the information given above
|
||||
applies also for every other Free Software Project. Contact
|
||||
`coordinator@translationproject.org' to make the `.pot' files available
|
||||
to the translation teams.
|
||||
|
||||
|
||||
187
ChangeLog
187
ChangeLog
@@ -1,3 +1,190 @@
|
||||
2014-07-25 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* .gitignore: Add a gitignore file for the project.
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Add testenv/Makefile to AC_CONFIG_FILES.
|
||||
* Makefile.am: Add testenv to SUBDIRS
|
||||
|
||||
2014-07-22 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Fix broken code for detecting libpsl
|
||||
|
||||
2014-07-21 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Fix check for Libpsl
|
||||
|
||||
2014-06-28 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* cfg.mk (local-checks-to-skip): Remove some checks.
|
||||
|
||||
2014-06-27 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* cfg.mk (VC_LIST_ALWAYS_EXCLUDE_REGEX): Ignore msdos/* and vms/* from
|
||||
syntax-check.
|
||||
|
||||
2014-06-22 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* configure.ac: Add check for uuid_create.
|
||||
|
||||
2014-06-11 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* NEWS: Remove repeated word.
|
||||
|
||||
* po/POTFILES.in: Add lib/regcomp.c.
|
||||
|
||||
* configure.ac: Do not depend on always defined macros.
|
||||
* vms/vms.h: Likewise.
|
||||
|
||||
* Makefile.am: Remove @VAR@ with $FOO.
|
||||
* util/Makefile.am: Likewise.
|
||||
|
||||
* ABOUT-NLS: Remove terminating empty lines.
|
||||
* MAILING-LIST: Likewise.
|
||||
* util/rmold.pl: Likewise.
|
||||
|
||||
* util/trunc.c (main): Ensure bindtextdomain is called.
|
||||
|
||||
2014-06-10 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* build-aux/build_info.pl: Remove trailing whitespaces.
|
||||
* configure.ac: Likewise.
|
||||
|
||||
2014-05-30 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Allow compilation without libpsl.
|
||||
* README.checkout: Add libpsl as a dependency.
|
||||
|
||||
2014-05-24 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* gnulib: update module.
|
||||
|
||||
2014-02-24 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* gnulib: update module.
|
||||
Reported by: Darshit Shah <darnir@gmail.com>.
|
||||
|
||||
2014-02-06 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* configure.ac: Update copyright years.
|
||||
|
||||
2013-12-22 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* gnulib: add git submodule.
|
||||
|
||||
2013-10-23 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Add --race-detection.
|
||||
* configure.ac: Remove redundant --enable-threads option.
|
||||
Add Metalink to configure summary
|
||||
|
||||
2013-07-02 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README.checkout: Add dependency on libmetalink.
|
||||
|
||||
2013-06-23 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* configure.ac: By default disable threads and metalink support.
|
||||
|
||||
2013-09-13 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* configure.ac: added a summary of build options
|
||||
fixed some indentations
|
||||
removed the unconditionally adding of libz with --with-ssl
|
||||
removed -lgcrypt and -lgpg-error for gnutls
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* configure.ac: Add testenv/Makefile to AC_CONFIG_FILES.
|
||||
* Makefile.am: Add testenv to SUBDIRS
|
||||
|
||||
2013-07-23 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* configure.ac: Remove AM_CONDITIONAL HAVE_NETTLE.
|
||||
Reported by: Darshit Shah <darnir@gmail.com>.
|
||||
|
||||
2013-07-13 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* configure.ac: check for libnettle when GNU TLS is used.
|
||||
|
||||
2013-05-17 Bykov Aleksey <gnfalex@rambler.ru>
|
||||
|
||||
* bootstrap: Add `mkostemp'
|
||||
|
||||
2012-10-07 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* configure.ac: Check for patchconf.
|
||||
|
||||
2012-09-23 Merinov Nikolay <kim.roader@gmail.com>
|
||||
|
||||
* m4/wget.m4 (WGET_FNMATCH): Add AC_LANG_SOURCE into
|
||||
AC_COMPILE_IFELSE in order to silence autoconf 2.68 warning.
|
||||
|
||||
2012-09-20 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* bootstrap: Update from gnulib.
|
||||
|
||||
2012-09-02 Nguyễn Thái Ngọc Duy <pclouds@gmail.com> (tiny change)
|
||||
|
||||
* po/POTFILES.in: Add more files.
|
||||
|
||||
2012-11-28 Domenico Chierico <spaghetty@gmail.com>
|
||||
|
||||
* bootstrap: update from upstream.
|
||||
* configure.ac: Change tests for iri/threads/metalink detection.
|
||||
|
||||
2012-08-03 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* bootstrap.conf : Add crypto/sha256 to the list of Gnulib modules used
|
||||
by this package.
|
||||
|
||||
2012-08-03 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* bootstrap.conf : Add crypto/sha1 to the list of Gnulib modules used
|
||||
by this package.
|
||||
|
||||
2012-07-29 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Check the availability of pthread library, before
|
||||
enabling thread support.
|
||||
|
||||
2012-07-27 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Update libmetalink check so that metalink support is
|
||||
not taken into consideration for compilation, if thread support is not
|
||||
desired.
|
||||
|
||||
2012-07-23 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Make Metalink check in configure.ac automatic by
|
||||
assigning auto to ENABLE_METALINK in AC_ARG_ENABLE macro. Update the
|
||||
libmetalink check accordingly.
|
||||
|
||||
2012-07-23 Micah Cowan <micah@cowan.name>
|
||||
|
||||
* bootstrap : Replace the bootstrap with the latest bootstrap from
|
||||
Gnulib.
|
||||
* bootstrap.conf : Remove the line "$build_aux/missing".
|
||||
|
||||
2012-07-22 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Correct the faulty assignment by assigning to CFLAGS
|
||||
instead of LIBS. Add AM_CONDITIONAL macro to assign a value to a
|
||||
variable(i.e. METALINK_IS_ENABLED) to be used in src/Metalink.am.
|
||||
|
||||
2012-07-21 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Update the check for libmetalink. The new version tries
|
||||
using pkg-config.
|
||||
|
||||
2012-07-20 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* configure.ac : Add AC_ARG_ENABLE macros to be able to check for the
|
||||
essential libraries for multi-threaded and metalink downloading support.
|
||||
Add checks for libmetalink and make essential additions to LIBS and
|
||||
CFLAGS if found, as well as prompting messages if it is not found.
|
||||
|
||||
2012-07-08 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* bootstrap: Update from gnulib.
|
||||
|
||||
@@ -47,4 +47,3 @@ for submitting and discussing patches to GNU Wget.
|
||||
|
||||
Messages from <wget-patches@sunsite.dk> are archived at
|
||||
`http://news.gmane.org/gmane.comp.web.wget.patches'.
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
# as that of the covered work.
|
||||
|
||||
#
|
||||
# Version: @VERSION@
|
||||
# Version: $(VERSION)
|
||||
#
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ distuninstallcheck_listfiles = find . -type f | \
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# subdirectories in the distribution
|
||||
SUBDIRS = lib src doc po tests util
|
||||
SUBDIRS = lib src doc po tests util testenv
|
||||
|
||||
EXTRA_DIST = ChangeLog.README MAILING-LIST \
|
||||
msdos/ChangeLog msdos/config.h msdos/Makefile.DJ \
|
||||
|
||||
48
NEWS
48
NEWS
@@ -6,6 +6,52 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU Wget bug reports to <bug-wget@gnu.org>.
|
||||
|
||||
* Changes in Wget X.Y.Z
|
||||
|
||||
** Use libpsl for verifying cookie domains
|
||||
|
||||
** Default progress bar output changed
|
||||
|
||||
** Introduce --show-progress to force display the progress bar
|
||||
|
||||
** Introduce --no-config.
|
||||
|
||||
** Introduce --start-pos to allow starting downloads from a specified position.
|
||||
|
||||
** Fix a problem with ISA Server Proxy and keep-alive connections.
|
||||
|
||||
* Changes in Wget 1.15
|
||||
|
||||
** Add support for --method.
|
||||
|
||||
** Add support for file names longer than MAX_FILE.
|
||||
|
||||
** Support FTP listing for the FTP Server on Windows Server 2008 R2.
|
||||
|
||||
** Fix a regression when -c and --content-disposition are used together.
|
||||
|
||||
** Support shorthand URLs in an input file.
|
||||
|
||||
** Fix -c with servers that don't specify a content-length.
|
||||
|
||||
** Add support for MD5-SESS
|
||||
|
||||
** Do not fail on non fatal GNU TLS alerts during handshake.
|
||||
|
||||
** Add support for --https-only. When used wget will follow only
|
||||
HTTPS links in recursive mode.
|
||||
|
||||
** Support Perfect-Forward Secrecy in --secure-protocol.
|
||||
|
||||
** Fix a problem with some IRI links that are not followed when contained in a
|
||||
HTML document.
|
||||
|
||||
** Support some FTP servers that return an empty list with "LIST -a".
|
||||
|
||||
** Specify Host with the HTTP CONNECT method.
|
||||
|
||||
** Use the correct HTTP method on a redirection.
|
||||
|
||||
* Changes in Wget 1.14
|
||||
|
||||
** Add support for content-on-error. It allows to store the HTTP
|
||||
@@ -640,7 +686,7 @@ ASCII type transfer:
|
||||
|
||||
wget "ftp://ftp.somewhere.com/welcome.msg;type=a"
|
||||
|
||||
** `--help' and `--version' options have been redone to to conform to
|
||||
** `--help' and `--version' options have been redone to conform to
|
||||
standards set by other GNU utilities.
|
||||
|
||||
** Wget should now be compilable under MS Windows environment. MS
|
||||
|
||||
@@ -4,8 +4,8 @@ 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, libidn and libiconv
|
||||
are not absolutely required):
|
||||
more of the following (note that gettext, OpenSSL, libidn, libiconv,
|
||||
libpsl and libmetalink are not absolutely required):
|
||||
|
||||
* [20]autoconf (currently, GNU Wget requires version 2.61). This is
|
||||
needed to generate the configure script from configure.in. This is
|
||||
@@ -68,6 +68,11 @@ Compiling From Repository Sources
|
||||
|
||||
* [34]git is used to fetch gnulib files trough the bootstrap.sh script.
|
||||
|
||||
* [45]libmetalink is required for compiling with Metalink support.
|
||||
|
||||
* [35]libpsl is required for using a public suffix list to check for valid
|
||||
cookie domains.
|
||||
|
||||
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
|
||||
that point, a shell script called bootstrap.sh has been provided. After
|
||||
@@ -96,21 +101,21 @@ Compiling From Repository Sources
|
||||
|
||||
Originally written by Hrvoje Niksic <hniksic@xemacs.org>.
|
||||
|
||||
* [35]Edit
|
||||
* [36]Comments
|
||||
* [37]Info
|
||||
* [38]Attachments
|
||||
* [36]Edit
|
||||
* [37]Comments
|
||||
* [38]Info
|
||||
* [39]Attachments
|
||||
* More Actions:
|
||||
[Raw Text................] Do
|
||||
|
||||
* [39]MoinMoin Powered
|
||||
* [40]Python Powered
|
||||
* [41]GPL licensed
|
||||
* [42]Valid HTML 4.01
|
||||
* [40]MoinMoin Powered
|
||||
* [41]Python Powered
|
||||
* [42]GPL licensed
|
||||
* [43]Valid HTML 4.01
|
||||
__________________________________________________________________
|
||||
|
||||
All content © 2007 Free Software Foundation. For terms of use,
|
||||
redistribution, and modification, please see the [43]WikiLicense page.
|
||||
redistribution, and modification, please see the [44]WikiLicense page.
|
||||
|
||||
References
|
||||
|
||||
@@ -129,12 +134,14 @@ References
|
||||
32. http://www.gnu.org/software/libidn/
|
||||
33. http://www.gnu.org/software/libiconv/
|
||||
34. http://git-scm.com/
|
||||
35. http://wget.addictivecode.org/CompilingRepoSources?action=edit&editor=text
|
||||
36. http://wget.addictivecode.org/CompilingRepoSources
|
||||
37. http://wget.addictivecode.org/CompilingRepoSources?action=info
|
||||
38. http://wget.addictivecode.org/CompilingRepoSources?action=AttachFile
|
||||
39. http://moinmo.in/
|
||||
40. http://moinmo.in/Python
|
||||
41. http://moinmo.in/GPL
|
||||
42. http://validator.w3.org/check?uri=referer
|
||||
43. http://wget.addictivecode.org/WikiLicense
|
||||
35. https://github.com/rockdaboot/libpsl
|
||||
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
|
||||
44. http://wget.addictivecode.org/WikiLicense
|
||||
45. https://launchpad.net/libmetalink
|
||||
|
||||
49
bootstrap
49
bootstrap
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2012-07-06.11; # UTC
|
||||
scriptversion=2012-07-19.14; # UTC
|
||||
|
||||
# Bootstrap this package from checked-out sources.
|
||||
|
||||
@@ -77,15 +77,32 @@ Running without arguments will suffice in most cases.
|
||||
EOF
|
||||
}
|
||||
|
||||
warn()
|
||||
# warnf_ FORMAT-STRING ARG1...
|
||||
warnf_ ()
|
||||
{
|
||||
for i
|
||||
do
|
||||
echo "$i"
|
||||
done | sed -e "s/^/$me: /" >&2
|
||||
warnf_format_=$1
|
||||
shift
|
||||
nl='
|
||||
'
|
||||
case $* in
|
||||
*$nl*) me_=$(printf "$me"|tr "$nl|" '??')
|
||||
printf "$warnf_format_" "$@" | sed "s|^|$me_: |" ;;
|
||||
*) printf "$me: $warnf_format_" "$@" ;;
|
||||
esac >&2
|
||||
}
|
||||
|
||||
die() { warn "$@"; exit 1; }
|
||||
# warn_ WORD1...
|
||||
warn_ ()
|
||||
{
|
||||
# If IFS does not start with ' ', set it and emit the warning in a subshell.
|
||||
case $IFS in
|
||||
' '*) warnf_ '%s\n' "$*";;
|
||||
*) (IFS=' '; warn_ "$@");;
|
||||
esac
|
||||
}
|
||||
|
||||
# die WORD1...
|
||||
die() { warn_ "$@"; exit 1; }
|
||||
|
||||
# Configuration.
|
||||
|
||||
@@ -197,6 +214,8 @@ use_git=true
|
||||
# otherwise find the first of the NAMES that can be run (i.e.,
|
||||
# supports --version). If found, set ENVVAR to the program name,
|
||||
# die otherwise.
|
||||
#
|
||||
# FIXME: code duplication, see also gnu-web-doc-update.
|
||||
find_tool ()
|
||||
{
|
||||
find_tool_envvar=$1
|
||||
@@ -335,8 +354,7 @@ grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \
|
||||
grep '^[ ]*AC_CONFIG_AUX_DIR('"$build_aux"')' configure.ac \
|
||||
>/dev/null && found_aux_dir=yes
|
||||
test $found_aux_dir = yes \
|
||||
|| die "expected line not found in configure.ac. Add the following:" \
|
||||
" AC_CONFIG_AUX_DIR([$build_aux])"
|
||||
|| die "configure.ac lacks 'AC_CONFIG_AUX_DIR([$build_aux])'; add it"
|
||||
|
||||
# If $build_aux doesn't exist, create it now, otherwise some bits
|
||||
# below will malfunction. If creating it, also mark it as ignored.
|
||||
@@ -442,7 +460,7 @@ check_versions() {
|
||||
automake-ng|aclocal-ng)
|
||||
app=${app%-ng}
|
||||
($app --version | grep '(GNU automake-ng)') >/dev/null 2>&1 || {
|
||||
warn "Error: '$app' not found or not from Automake-NG"
|
||||
warn_ "Error: '$app' not found or not from Automake-NG"
|
||||
ret=1
|
||||
continue
|
||||
} ;;
|
||||
@@ -452,20 +470,21 @@ check_versions() {
|
||||
# so we have to rely on $? rather than get_version.
|
||||
$app --version >/dev/null 2>&1
|
||||
if [ 126 -le $? ]; then
|
||||
warn "Error: '$app' not found"
|
||||
warn_ "Error: '$app' not found"
|
||||
ret=1
|
||||
fi
|
||||
else
|
||||
# Require app to produce a new enough version string.
|
||||
inst_ver=$(get_version $app)
|
||||
if [ ! "$inst_ver" ]; then
|
||||
warn "Error: '$app' not found"
|
||||
warn_ "Error: '$app' not found"
|
||||
ret=1
|
||||
else
|
||||
latest_ver=$(sort_ver $req_ver $inst_ver | cut -d' ' -f2)
|
||||
if [ ! "$latest_ver" = "$inst_ver" ]; then
|
||||
warn "Error: '$app' version == $inst_ver is too old" \
|
||||
" '$app' version >= $req_ver is required"
|
||||
warnf_ '%s\n' \
|
||||
"Error: '$app' version == $inst_ver is too old" \
|
||||
" '$app' version >= $req_ver is required"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
@@ -761,7 +780,7 @@ version_controlled_file() {
|
||||
grep -F "/${file##*/}/" "$parent/CVS/Entries" 2>/dev/null |
|
||||
grep '^/[^/]*/[0-9]' > /dev/null
|
||||
else
|
||||
warn "no version control for $file?"
|
||||
warn_ "no version control for $file?"
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -52,8 +52,10 @@ maintainer-makefile
|
||||
mbtowc
|
||||
mkdir
|
||||
mkstemp
|
||||
mkostemp
|
||||
crypto/md5
|
||||
crypto/sha1
|
||||
crypto/sha256
|
||||
pipe
|
||||
quote
|
||||
quotearg
|
||||
|
||||
@@ -100,7 +100,7 @@ EOC
|
||||
EOC
|
||||
}
|
||||
print $fh <<EOC;
|
||||
#else
|
||||
#else
|
||||
"-$name",
|
||||
#endif
|
||||
|
||||
|
||||
5
cfg.mk
5
cfg.mk
@@ -4,7 +4,6 @@ local-checks-to-skip = \
|
||||
sc_const_long_option \
|
||||
sc_error_message_uppercase \
|
||||
sc_file_system \
|
||||
sc_makefile_TAB_only_indentation \
|
||||
sc_immutable_NEWS \
|
||||
sc_copyright_check \
|
||||
sc_makefile_path_separator_check \
|
||||
@@ -13,10 +12,8 @@ local-checks-to-skip = \
|
||||
sc_two_space_separator_in_usage \
|
||||
sc_useless_cpp_parens \
|
||||
\
|
||||
sc_space_tab \
|
||||
sc_prohibit_atoi_atof \
|
||||
sc_prohibit_strcmp \
|
||||
sc_makefile_check \
|
||||
sc_cast_of_alloca_return_value \
|
||||
sc_cast_of_x_alloc_return_value \
|
||||
sc_prohibit_S_IS_definition \
|
||||
@@ -27,3 +24,5 @@ local-checks-to-skip = \
|
||||
#SHELL=bash -x
|
||||
show-vc-list-except:
|
||||
@$(VC_LIST_EXCEPT)
|
||||
|
||||
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|((msdos|vms)/.*)$$
|
||||
|
||||
289
configure.ac
289
configure.ac
@@ -1,6 +1,6 @@
|
||||
dnl Template file for GNU Autoconf
|
||||
dnl Copyright (C) 1995, 1996, 1997, 2001, 2007, 2008, 2009, 2010, 2011
|
||||
dnl Free Software Foundation, Inc.
|
||||
dnl Copyright (C) 1995, 1996, 1997, 2001, 2007, 2008, 2009, 2010, 2011, 2012,
|
||||
dnl 2013, 2014 Free Software Foundation, Inc.
|
||||
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
@@ -61,6 +61,16 @@ dnl
|
||||
dnl Process features.
|
||||
dnl
|
||||
|
||||
ENABLE_PSL=no
|
||||
AC_ARG_WITH(libpsl,
|
||||
AS_HELP_STRING([--without-libpsl],
|
||||
[disable support for libpsl cookie checking.]),
|
||||
[],
|
||||
[AC_SEARCH_LIBS(psl_builtin, psl,
|
||||
[ENABLE_PSL=yes; AC_DEFINE([HAVE_LIBPSL], [1], [PSL Support Enabled])],
|
||||
[AC_MSG_WARN(*** libpsl not found. Falling back to Wget builtin cookie checking.)])
|
||||
])
|
||||
|
||||
AC_ARG_WITH(ssl,
|
||||
[[ --without-ssl disable SSL autodetection
|
||||
--with-ssl={gnutls,openssl} specify the SSL backend. GNU TLS is the default.]])
|
||||
@@ -90,6 +100,18 @@ ENABLE_DEBUG=$enableval, ENABLE_DEBUG=yes)
|
||||
test x"${ENABLE_DEBUG}" = xyes && AC_DEFINE([ENABLE_DEBUG], 1,
|
||||
[Define if you want the debug output support compiled in.])
|
||||
|
||||
AC_ARG_ENABLE(metalink,
|
||||
[ --disable-metalink disable support for metalink file format],
|
||||
ENABLE_METALINK=$enableval, ENABLE_METALINK=no)
|
||||
test x"${ENABLE_METALINK}" = xyes && AC_DEFINE([ENABLE_METALINK], 1,
|
||||
[Define if you want the metalink file format support compiled in.])
|
||||
|
||||
AC_ARG_ENABLE(race-detection,
|
||||
[ --enable-race-detection enable support for detecting race conditions],
|
||||
ENABLE_RACES=$enableval, ENABLE_RACES=no)
|
||||
test x"${ENABLE_RACES}" = xyes && AC_DEFINE([ENABLE_RACES], 1,
|
||||
[Define if you want runtime Race Detection enabled.])
|
||||
|
||||
dnl
|
||||
dnl Find the compiler
|
||||
dnl
|
||||
@@ -142,8 +164,7 @@ AC_C_VOLATILE
|
||||
|
||||
dnl Check for basic headers, even though we expect them to exist and
|
||||
dnl #include them unconditionally in the code. Their detection is
|
||||
dnl still needed because test programs used by Autoconf macros check
|
||||
dnl for STDC_HEADERS, HAVE_SYS_TYPES_H, etc. before using them.
|
||||
dnl still needed because test programs used by Autoconf macros check.
|
||||
dnl Without the checks they will fail to be included in test programs,
|
||||
dnl which will subsequently fail.
|
||||
AC_HEADER_STDC
|
||||
@@ -184,9 +205,7 @@ AC_CHECK_TYPES([uint32_t, uintptr_t, intptr_t, int64_t])
|
||||
AC_CHECK_TYPES(sig_atomic_t, [], [], [
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#if HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
])
|
||||
|
||||
@@ -198,7 +217,7 @@ dnl Checks for library functions.
|
||||
dnl
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_FSEEKO
|
||||
AC_CHECK_FUNCS(strptime timegm vsnprintf vasprintf drand48)
|
||||
AC_CHECK_FUNCS(strptime timegm vsnprintf vasprintf drand48 pathconf)
|
||||
AC_CHECK_FUNCS(strtoll usleep ftello sigblock sigsetjmp memrchr wcwidth mbtowc)
|
||||
AC_CHECK_FUNCS(sleep symlink utime)
|
||||
|
||||
@@ -238,57 +257,54 @@ dnl Checks for libraries.
|
||||
dnl
|
||||
|
||||
AS_IF([test x"$with_zlib" != xno], [
|
||||
with_zlib=yes
|
||||
AC_CHECK_LIB(z, compress)
|
||||
])
|
||||
|
||||
AS_IF([test x"$with_ssl" = xopenssl], [
|
||||
dnl some versions of openssl use zlib compression
|
||||
AC_CHECK_LIB(z, compress)
|
||||
dnl As of this writing (OpenSSL 0.9.6), the libcrypto shared library
|
||||
dnl doesn't record its dependency on libdl, so we need to make sure
|
||||
dnl -ldl ends up in LIBS on systems that have it. Most OSes use
|
||||
dnl dlopen(), but HP-UX uses shl_load().
|
||||
AC_CHECK_LIB(dl, dlopen, [], [
|
||||
AC_CHECK_LIB(dl, shl_load)
|
||||
])
|
||||
|
||||
dnl As of this writing (OpenSSL 0.9.6), the libcrypto shared library
|
||||
dnl doesn't record its dependency on libdl, so we need to make sure
|
||||
dnl -ldl ends up in LIBS on systems that have it. Most OSes use
|
||||
dnl dlopen(), but HP-UX uses shl_load().
|
||||
AC_CHECK_LIB(dl, dlopen, [], [
|
||||
AC_CHECK_LIB(dl, shl_load)
|
||||
])
|
||||
ssl_found=no
|
||||
case $host_os in
|
||||
*mingw32* )
|
||||
dnl prefer link to openssl dlls if possible. if not then fallback on static libs. if not then error
|
||||
|
||||
ssl_found=no
|
||||
case $host_os in
|
||||
*mingw32* )
|
||||
dnl prefer link to openssl dlls if possible. if not then fallback on static libs. if not then error
|
||||
|
||||
AC_CHECK_LIB(eay32, EVP_MD_CTX_init)
|
||||
if test x"$ac_cv_lib_eay32_EVP_MD_CTX_init" != xno
|
||||
then
|
||||
AC_CHECK_LIB(ssl32, SSL_connect, [
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([Enabling support for SSL via OpenSSL (shared)])
|
||||
AC_LIBOBJ([openssl])
|
||||
LIBS="${LIBS} -lssl32"
|
||||
AC_DEFINE([HAVE_LIBSSL32], [1], [Define to 1 if you have the `ssl32' library (-lssl32).])
|
||||
],
|
||||
AC_MSG_ERROR([openssl not found: shared lib eay32 found but ssl32 not found]))
|
||||
|
||||
else
|
||||
LIBS+=' -lgdi32'
|
||||
dnl fallback and test static libs
|
||||
fi
|
||||
dnl add zdll lib as dep for above tests?
|
||||
;;
|
||||
esac
|
||||
AC_CHECK_LIB(eay32, EVP_MD_CTX_init)
|
||||
if test x"$ac_cv_lib_eay32_EVP_MD_CTX_init" != xno
|
||||
then
|
||||
AC_CHECK_LIB(ssl32, SSL_connect, [
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([Enabling support for SSL via OpenSSL (shared)])
|
||||
AC_LIBOBJ([openssl])
|
||||
LIBS="${LIBS} -lssl32"
|
||||
AC_DEFINE([HAVE_LIBSSL32], [1], [Define to 1 if you have the `ssl32' library (-lssl32).])
|
||||
],
|
||||
AC_MSG_ERROR([openssl not found: shared lib eay32 found but ssl32 not found]))
|
||||
|
||||
AS_IF([test x$ssl_found != xyes],
|
||||
[
|
||||
dnl Now actually check for -lssl if it wasn't already found
|
||||
AC_LIB_HAVE_LINKFLAGS([ssl], [crypto z], [
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
#include <openssl/md5.h>
|
||||
else
|
||||
LIBS+=' -lgdi32'
|
||||
dnl fallback and test static libs
|
||||
fi
|
||||
dnl add zdll lib as dep for above tests?
|
||||
;;
|
||||
esac
|
||||
|
||||
AS_IF([test x$ssl_found != xyes], [
|
||||
dnl Now actually check for -lssl if it wasn't already found
|
||||
AC_LIB_HAVE_LINKFLAGS([ssl], [crypto], [
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
#include <openssl/md5.h>
|
||||
], [SSL_library_init ()])
|
||||
if test x"$LIBSSL" != x
|
||||
then
|
||||
@@ -300,33 +316,30 @@ AS_IF([test x$ssl_found != xyes],
|
||||
then
|
||||
AC_MSG_ERROR([--with-ssl=openssl was given, but SSL is not available.])
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
], [
|
||||
# --with-ssl is not gnutls: check if it's no
|
||||
# --with-ssl is not openssl: check if it's no
|
||||
AS_IF([test x"$with_ssl" != xno], [
|
||||
dnl Now actually check for -lssl
|
||||
dnl default is -lgnutls
|
||||
with_ssl=gnutls
|
||||
|
||||
AC_CHECK_LIB(z, compress)
|
||||
AC_CHECK_LIB(gpg-error, gpg_err_init)
|
||||
AC_CHECK_LIB(gcrypt, gcry_control)
|
||||
|
||||
dnl Now actually check for -lssl
|
||||
AC_LIB_HAVE_LINKFLAGS([gnutls], [], [
|
||||
dnl Now actually check for -lgnutls
|
||||
AC_LIB_HAVE_LINKFLAGS([gnutls], [], [
|
||||
#include <gnutls/gnutls.h>
|
||||
], [gnutls_global_init()])
|
||||
if test x"$LIBGNUTLS" != x
|
||||
then
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([compiling in support for SSL via GnuTLS])
|
||||
AC_LIBOBJ([gnutls])
|
||||
LIBS="$LIBGNUTLS $LIBS"
|
||||
else
|
||||
AC_MSG_ERROR([--with-ssl was given, but GNUTLS is not available.])
|
||||
fi
|
||||
], [gnutls_global_init()])
|
||||
if test x"$LIBGNUTLS" != x
|
||||
then
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([compiling in support for SSL via GnuTLS])
|
||||
AC_LIBOBJ([gnutls])
|
||||
LIBS="$LIBGNUTLS $LIBS"
|
||||
else
|
||||
AC_MSG_ERROR([--with-ssl=gnutls was given, but GNUTLS is not available.])
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(gnutls_priority_set_direct)
|
||||
]) # endif: --with-ssl == no?
|
||||
AC_CHECK_FUNCS(gnutls_priority_set_direct)
|
||||
]) # endif: --with-ssl != no?
|
||||
]) # endif: --with-ssl == openssl?
|
||||
|
||||
dnl Enable NTLM if requested and if SSL is available.
|
||||
@@ -334,19 +347,105 @@ if test x"$LIBSSL" != x || test "$ac_cv_lib_ssl32_SSL_connect" = yes
|
||||
then
|
||||
if test x"$ENABLE_NTLM" != xno
|
||||
then
|
||||
ENABLE_NTLM=yes
|
||||
AC_DEFINE([ENABLE_NTLM], 1,
|
||||
[Define if you want the NTLM authorization support compiled in.])
|
||||
AC_LIBOBJ([http-ntlm])
|
||||
fi
|
||||
else
|
||||
dnl If SSL is unavailable and the user explicitly requested NTLM,
|
||||
dnl abort.
|
||||
if test x"$ENABLE_NTLM" = xyes
|
||||
AC_CHECK_LIB(nettle, nettle_md4_init, [HAVE_NETTLE=yes], [HAVE_NETTLE=no; AC_MSG_WARN(*** libnettle was not found. You will not be able to use NTLM)])
|
||||
|
||||
if test x"$HAVE_NETTLE" = xyes
|
||||
then
|
||||
AC_MSG_ERROR([NTLM authorization requested and OpenSSL not found; aborting])
|
||||
AC_SUBST(NETTLE_LIBS, "-lnettle")
|
||||
AC_DEFINE([HAVE_NETTLE], [1], [Use libnettle])
|
||||
if test x"$ENABLE_NTLM" != xno
|
||||
then
|
||||
ENABLE_NTLM=yes
|
||||
AC_DEFINE([ENABLE_NTLM], 1,
|
||||
[Define if you want the NTLM authorization support compiled in.])
|
||||
AC_LIBOBJ([http-ntlm])
|
||||
LIBS="$NETTLE_LIBS $LIBS"
|
||||
fi
|
||||
else
|
||||
dnl If SSL is unavailable and the user explicitly requested NTLM,
|
||||
dnl abort.
|
||||
if test x"$ENABLE_NTLM" = xyes
|
||||
then
|
||||
AC_MSG_ERROR([NTLM authorization requested and SSL not enabled; aborting])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
AS_IF([test x"$ENABLE_THREADS" != xno],[
|
||||
AC_CHECK_LIB(pthread, pthread_create, [
|
||||
dnl AC_CHECK_LIB(semaphore, sem_init, [
|
||||
threads=yes
|
||||
LIBS="${LIBS} -lpthread"
|
||||
AC_DEFINE([ENABLE_THREADS], 1,
|
||||
[Define if you want the thread support compiled in.])
|
||||
AC_MSG_NOTICE([compiling with support for threads])
|
||||
dnl ],[
|
||||
dnl threads=no
|
||||
dnl if test x"$ENABLE_THREADS" == xyes
|
||||
dnl then
|
||||
dnl AC_MSG_ERROR([Could not find the sem_init function in semaphore.])
|
||||
dnl fi
|
||||
dnl ])
|
||||
],[
|
||||
threads=no
|
||||
if test x"$ENABLE_THREADS" == xyes
|
||||
then
|
||||
AC_MSG_ERROR([Could not find the pthread_create function in pthread.])
|
||||
fi
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test x"$ENABLE_RACES" != xno],[
|
||||
CFLAGS="$CFLAGS -fsanitize=thread -fPIE";
|
||||
LDFLAGS="$LDFLAGS -fsanitize=thread -pie";
|
||||
])
|
||||
|
||||
AS_IF([test x"$ENABLE_METALINK" != xno],[
|
||||
dnl If metalink support is requested
|
||||
PKG_CHECK_MODULES(LIBMETALINK, libmetalink, [
|
||||
dnl If metalink module is found
|
||||
LIBS="$LIBMETALINK_LIBS $LIBS"
|
||||
CFLAGS="$LIBMETALINK_CFLAGS $CFLAGS"
|
||||
AC_DEFINE([ENABLE_METALINK], 1,
|
||||
[Define if you want the metalink support compiled in.])
|
||||
|
||||
AC_CHECK_LIB(metalink, metalink_parse_file, [
|
||||
if test x"$DISABLE_THREADS" == xyes
|
||||
then
|
||||
AC_MSG_ERROR([Metalink support depends on threads, which are requested to be disabled.])
|
||||
elif test "X$threads" != "Xyes"
|
||||
then
|
||||
AC_MSG_ERROR([Metalink support depends on threads, support for which could not be enabled.])
|
||||
else
|
||||
metalink=yes
|
||||
AC_MSG_NOTICE([compiling in support for metalink])
|
||||
fi
|
||||
], [
|
||||
if test x"$ENABLE_METALINK" == xyes
|
||||
then
|
||||
AC_MSG_ERROR([Could not find the metalink_parse_file function in libmetalink.])
|
||||
fi
|
||||
])
|
||||
], [
|
||||
dnl If metalink module is not found
|
||||
if test x"$ENABLE_METALINK" == xyes
|
||||
then
|
||||
AC_MSG_ERROR([libmetalink not found])
|
||||
fi
|
||||
])
|
||||
],[
|
||||
dnl If metalink support is not requested
|
||||
metalink=no
|
||||
AC_MSG_NOTICE([compiling without support for metalink])
|
||||
])
|
||||
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Checks for IPv6
|
||||
dnl **********************************************************************
|
||||
@@ -523,6 +622,12 @@ fi
|
||||
dnl
|
||||
dnl Check for UUID
|
||||
dnl
|
||||
AC_CHECK_HEADER(uuid.h,
|
||||
AC_CHECK_FUNC(uuid, uuid_create,
|
||||
[AC_DEFINE([HAVE_UUID_CREATE], 1,
|
||||
[Define if uuid_create is available.])
|
||||
])
|
||||
)
|
||||
|
||||
AC_CHECK_HEADER(uuid/uuid.h,
|
||||
AC_CHECK_LIB(uuid, uuid_generate,
|
||||
@@ -544,16 +649,38 @@ AC_CHECK_HEADER(pcre.h,
|
||||
])
|
||||
)
|
||||
|
||||
|
||||
dnl Needed by src/Makefile.am
|
||||
AM_CONDITIONAL([IRI_IS_ENABLED], [test "X$iri" != "Xno"])
|
||||
|
||||
dnl Needed by src/Makefile.am
|
||||
AM_CONDITIONAL([IRI_IS_ENABLED], [test "X$iri" == "Xyes"])
|
||||
AM_CONDITIONAL([METALINK_IS_ENABLED], [test "X$metalink" == "Xyes"])
|
||||
AM_CONDITIONAL([THREADS_ARE_ENABLED], [test "X$threads" == "Xyes"])
|
||||
AM_CONDITIONAL([RACE_CHECKING_IS_ENABLED], [test "X$race-detection" == "Xyes"])
|
||||
|
||||
dnl
|
||||
dnl Create output
|
||||
dnl
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile util/Makefile
|
||||
po/Makefile.in tests/Makefile tests/WgetTest.pm
|
||||
lib/Makefile])
|
||||
lib/Makefile testenv/Makefile])
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_NOTICE([Summary of build options:
|
||||
|
||||
Version: $PACKAGE_VERSION
|
||||
Host OS: $host_os
|
||||
Install prefix: $prefix
|
||||
Compiler: $CC
|
||||
CFlags: $CFLAGS $CPPFLAGS
|
||||
LDFlags: $LDFLAGS
|
||||
Libs: $LIBS
|
||||
SSL: $with_ssl
|
||||
Zlib: $with_zlib
|
||||
PSL: $ENABLE_PSL
|
||||
Digest: $ENABLE_DIGEST
|
||||
NTLM: $ENABLE_NTLM
|
||||
OPIE: $ENABLE_OPIE
|
||||
Metalink: $ENABLE_METALINK
|
||||
Debugging: $ENABLE_DEBUG
|
||||
Race Detection: $ENABLE_RACES
|
||||
])
|
||||
|
||||
123
doc/ChangeLog
123
doc/ChangeLog
@@ -1,3 +1,126 @@
|
||||
2014-08-03 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* wget.texi (Download Options): Fix texinfo warning.
|
||||
|
||||
2014-06-11 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.am: Remove @VAR@ with $FOO.
|
||||
|
||||
* fdl.texi: Remove terminating empty lines.
|
||||
|
||||
2014-06-10 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* wget.texi: Remove trailing whitespaces.
|
||||
|
||||
* fdl.texi: Copy from gnulib.
|
||||
|
||||
2014-05-24 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* wget.texi: Document noscroll parameter to progress=bar
|
||||
|
||||
2014-05-01 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* wget.texi: Add documentation for --show-progress
|
||||
|
||||
2014-02-10 Yousong Zhou <yszhou4tech@gmail.com>
|
||||
|
||||
* wget.texi: Add documentation for --start-pos.
|
||||
|
||||
2013-12-29 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* wget.texi: Update to GFDL 1.3.
|
||||
|
||||
2013-12-22 Mike Frysinger <vapier@gentoo.org>
|
||||
|
||||
* sample.wgetrc: add links to the manual.
|
||||
|
||||
2013-10-06 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* wget.texi: add/explain quoting of wildcard patterns
|
||||
|
||||
2013-09-04 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* sample.wgetrc: added "secureprotocol" example
|
||||
* wget.texi (HTTPS (SSL/TLS) Options): Document PFS.
|
||||
|
||||
2013-08-23 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* sample.wgetrc: added "httpsonly" example
|
||||
|
||||
2013-08-22 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* wget.texi: added description for --https-only
|
||||
|
||||
2013-08-13 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* wget.texi (Download Options): Fix misspelling.
|
||||
|
||||
2013-07-09 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* wget.texi (Download Options): Add documentation for --backups.
|
||||
(Wgetrc Commands): Add documentation for backups.
|
||||
Reported by: Tomas Hozza <thozza@redhat.com>.
|
||||
|
||||
2013-07-11 Tomas Hozza <thozza@redhat.com>
|
||||
|
||||
* wget.texi: Document --regex-type and --preserve-permissions.
|
||||
|
||||
2013-07-04 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* wget.texi (Download Options): Use '@item' instead of '@itemx'.
|
||||
Reported by: Darshit Shah <darnir@gmail.com>.
|
||||
|
||||
2013-06-17 Dave Reisner <dreisner@archlinux.org> (tiny change)
|
||||
|
||||
* texi2pod.pl: Fix formatting error that causes build to fail with
|
||||
Perl 5.18
|
||||
|
||||
2013-06-17 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* wget.texi (POST): Explain the new redirection rules.
|
||||
* wget.texi (Other HTTP Methods): Same.
|
||||
* wget.texi (body-data): Fix typo in description.
|
||||
|
||||
2013-05-10 Darshit Shah <darnir@gmail.com> (tiny change)
|
||||
|
||||
* wget.texi (No of tries): Fix typo to make it clear that --tries
|
||||
option sets number of tries not retries.
|
||||
Reported by: Hauke Hoffman <haukebjoernhoffman@googlemail.com>
|
||||
|
||||
2013-04-28 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* wget.texi (Types of Files...): Document --accept-regex,
|
||||
--reject-regex.
|
||||
Reported by: Tomas Hozza <thozza@redhat.com>.
|
||||
|
||||
2013-04-14 Giuseppe Scrivano <gscrivano@gnu.org>
|
||||
|
||||
* wget.texi (Download Options): Document "mega" dot style.
|
||||
|
||||
2013-04-05 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* doc/wget.texi: Fix ambiguous wording in --post-data section. Make it
|
||||
clear that wget does not check for the format of the post-data.
|
||||
* doc/wget.texi: Add documentation for --method, --body-data and
|
||||
--body-file.
|
||||
|
||||
2012-10-08 Stefano Lattarini <stefano.lattarini@gmail.com> (tiny change)
|
||||
|
||||
docs: fix errors and warnings with Texinfo 5
|
||||
Or rather, with the development version 4.13.90, which will
|
||||
eventually become Texinfo 5.0.
|
||||
* wget.texi: Use '@item' instead of '@itemx' in several places,
|
||||
as Texinfo 5 refuses to process an '@itemx' that is not preceded
|
||||
by an '@item'.
|
||||
|
||||
2012-08-28 Tim Ruehsen <tim.ruehsen@gmx.de>
|
||||
|
||||
* doc/wget.texi: remove -nv from --report-speed
|
||||
|
||||
2012-08-14 Ilim Ugur <ilimugur@gmail.com>
|
||||
|
||||
* wget.texi: Document --metalink-file and --retries.
|
||||
|
||||
2012-08-04 mancha <mancha@mac.hush.com> (tiny change)
|
||||
|
||||
* wget.texi: Export ENVIRONMENT to the man page.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# Version: @VERSION@
|
||||
# Version: $(VERSION)
|
||||
#
|
||||
|
||||
# Program to convert DVI files to PostScript
|
||||
@@ -28,7 +28,6 @@ manext = 1
|
||||
RM = rm -f
|
||||
|
||||
TEXI2POD = $(srcdir)/texi2pod.pl
|
||||
POD2MAN = @POD2MAN@
|
||||
MAN = wget.$(manext)
|
||||
WGETRC = $(sysconfdir)/wgetrc
|
||||
SAMPLERCTEXI = sample.wgetrc.munged_for_texi_inclusion
|
||||
@@ -39,7 +38,7 @@ SAMPLERCTEXI = sample.wgetrc.munged_for_texi_inclusion
|
||||
|
||||
man_MANS = $(MAN)
|
||||
|
||||
all: wget.info @COMMENT_IF_NO_POD2MAN@$(MAN)
|
||||
all: wget.info $(COMMENT_IF_NO_POD2MAN)$(MAN)
|
||||
|
||||
everything: all wget_us.ps wget_a4.ps wget_toc.html
|
||||
|
||||
@@ -57,7 +56,7 @@ wget.pod: $(srcdir)/wget.texi version.texi
|
||||
$(TEXI2POD) -D VERSION="$(VERSION)" $(srcdir)/wget.texi $@
|
||||
|
||||
$(MAN): wget.pod
|
||||
$(POD2MAN) --center="GNU Wget" --release="GNU Wget @VERSION@" $? > $@
|
||||
$(POD2MAN) --center="GNU Wget" --release="GNU Wget $(VERSION)" $? > $@
|
||||
|
||||
#wget.cat: $(MAN)
|
||||
# nroff -man $? > $@
|
||||
@@ -76,10 +75,10 @@ wget_toc.html: $(srcdir)/wget.texi
|
||||
#
|
||||
|
||||
# install all the documentation
|
||||
install-data-local: install.wgetrc @COMMENT_IF_NO_POD2MAN@install.man
|
||||
install-data-local: install.wgetrc $(COMMENT_IF_NO_POD2MAN)install.man
|
||||
|
||||
# uninstall all the documentation
|
||||
uninstall-local: @COMMENT_IF_NO_POD2MAN@uninstall.man
|
||||
uninstall-local: $(COMMENT_IF_NO_POD2MAN)uninstall.man
|
||||
|
||||
|
||||
# install man page, creating install directory if necessary
|
||||
|
||||
26
doc/fdl.texi
26
doc/fdl.texi
@@ -5,8 +5,7 @@
|
||||
@c hence no sectioning command or @node.
|
||||
|
||||
@display
|
||||
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008, 2009, 2010, 2011
|
||||
Free Software Foundation, Inc.
|
||||
Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
|
||||
@uref{http://fsf.org/}
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
@@ -93,16 +92,16 @@ An image format is not Transparent if used for any substantial amount
|
||||
of text. A copy that is not ``Transparent'' is called ``Opaque''.
|
||||
|
||||
Examples of suitable formats for Transparent copies include plain
|
||||
@sc{ascii} without markup, Texinfo input format, La@TeX{} input
|
||||
format, @acronym{SGML} or @acronym{XML} using a publicly available
|
||||
@acronym{DTD}, and standard-conforming simple @acronym{HTML},
|
||||
PostScript or @acronym{PDF} designed for human modification. Examples
|
||||
of transparent image formats include @acronym{PNG}, @acronym{XCF} and
|
||||
@acronym{JPG}. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, @acronym{SGML} or
|
||||
@acronym{XML} for which the @acronym{DTD} and/or processing tools are
|
||||
not generally available, and the machine-generated @acronym{HTML},
|
||||
PostScript or @acronym{PDF} produced by some word processors for
|
||||
ASCII without markup, Texinfo input format, La@TeX{} input
|
||||
format, SGML or XML using a publicly available
|
||||
DTD, and standard-conforming simple HTML,
|
||||
PostScript or PDF designed for human modification. Examples
|
||||
of transparent image formats include PNG, XCF and
|
||||
JPG@. Opaque formats include proprietary formats that can be
|
||||
read and edited only by proprietary word processors, SGML or
|
||||
XML for which the DTD and/or processing tools are
|
||||
not generally available, and the machine-generated HTML,
|
||||
PostScript or PDF produced by some word processors for
|
||||
output purposes only.
|
||||
|
||||
The ``Title Page'' means, for a printed book, the title page itself,
|
||||
@@ -482,7 +481,7 @@ license notices just after the title page:
|
||||
@end smallexample
|
||||
|
||||
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
|
||||
replace the ``with@dots{}Texts.'' line with this:
|
||||
replace the ``with@dots{}Texts.''@: line with this:
|
||||
|
||||
@smallexample
|
||||
@group
|
||||
@@ -504,4 +503,3 @@ to permit their use in free software.
|
||||
@c Local Variables:
|
||||
@c ispell-local-pdict: "ispell-dict"
|
||||
@c End:
|
||||
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
## You can use this file to change the default behaviour of wget or to
|
||||
## avoid having to type many many command-line options. This file does
|
||||
## not contain a comprehensive list of commands -- look at the manual
|
||||
## to find out what you can put into this file.
|
||||
## to find out what you can put into this file. You can find this here:
|
||||
## $ info wget.info 'Startup File'
|
||||
## Or online here:
|
||||
## https://www.gnu.org/software/wget/manual/wget.html#Startup-File
|
||||
##
|
||||
## Wget initialization file can reside in /usr/local/etc/wgetrc
|
||||
## (global, for all users) or $HOME/.wgetrc (for a single user).
|
||||
@@ -123,3 +126,9 @@
|
||||
|
||||
# Force the default remote server encoding
|
||||
#remoteencoding = UTF-8
|
||||
|
||||
# Turn on to prevent following non-HTTPS links when in recursive mode
|
||||
#httpsonly = off
|
||||
|
||||
# Tune HTTPS security (auto, SSLv2, SSLv3, TLSv1, PFS)
|
||||
#secureprotocol = auto
|
||||
|
||||
@@ -291,7 +291,7 @@ while(<$inf>) {
|
||||
if (defined $1) {
|
||||
my $thing = $1;
|
||||
if ($ic =~ /\@asis/) {
|
||||
$_ = "\n=item $thing\n";
|
||||
$_ = "\n=item C<$thing>\n";
|
||||
} else {
|
||||
# Entity escapes prevent munging by the <> processing below.
|
||||
$_ = "\n=item $ic\<$thing\>\n";
|
||||
|
||||
228
doc/wget.texi
228
doc/wget.texi
@@ -47,11 +47,11 @@ notice identical to this one except for the removal of this paragraph
|
||||
(this paragraph not being relevant to the printed manual).
|
||||
@end ignore
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.2 or
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
|
||||
copy of the license is included in the section entitled ``GNU Free
|
||||
Documentation License''.
|
||||
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
|
||||
Texts. A copy of the license is included in the section entitled
|
||||
``GNU Free Documentation License''.
|
||||
@c man end
|
||||
@end copying
|
||||
|
||||
@@ -479,8 +479,7 @@ Turn off verbose without being completely quiet (use @samp{-q} for
|
||||
that), which means that error messages and basic information still get
|
||||
printed.
|
||||
|
||||
@item -nv
|
||||
@itemx --report-speed=@var{type}
|
||||
@item --report-speed=@var{type}
|
||||
Output bandwidth as @var{type}. The only accepted value is @samp{bits}.
|
||||
|
||||
@cindex input-file
|
||||
@@ -534,6 +533,22 @@ would be resolved to @samp{http://foo/baz/b.html}.
|
||||
@cindex specify config
|
||||
@item --config=@var{FILE}
|
||||
Specify the location of a startup file you wish to use.
|
||||
|
||||
@cindex metalink
|
||||
@item --metalink=@var{FILE}
|
||||
Read @sc{url}s from a local or external metalink @var{file}. If @samp{-} is
|
||||
specified as @var{file}, @sc{url}s are read from the standard input.
|
||||
(Use @samp{./-} to read from a file literally named @samp{-}.)
|
||||
|
||||
If this function is used, no @sc{url}s need be present on the command
|
||||
line.
|
||||
|
||||
If the @var{file} is an external one, the document will be automatically
|
||||
downloaded and will not be kept even after wget terminates.
|
||||
|
||||
See option @samp{--jobs} to enable multi-threaded downloads from metalink
|
||||
files, option @samp{--retries} to set a number of retries for downloading a @var{file}
|
||||
in case of failure.
|
||||
@end table
|
||||
|
||||
@node Download Options, Directory Options, Logging and Input File Options, Invoking
|
||||
@@ -551,14 +566,19 @@ IPs.
|
||||
|
||||
@cindex retries
|
||||
@cindex tries
|
||||
@cindex number of retries
|
||||
@cindex number of tries
|
||||
@item -t @var{number}
|
||||
@itemx --tries=@var{number}
|
||||
Set number of retries to @var{number}. Specify 0 or @samp{inf} for
|
||||
Set number of tries to @var{number}. Specify 0 or @samp{inf} for
|
||||
infinite retrying. The default is to retry 20 times, with the exception
|
||||
of fatal errors like ``connection refused'' or ``not found'' (404),
|
||||
which are not retried.
|
||||
|
||||
@item --retries=@var{number}
|
||||
Set number of retries for a file specified in a metalink file to @var{number}.
|
||||
Specify 0 or @samp{inf} for no retrying in case of failed attempt. The default
|
||||
is to retry 1 time.
|
||||
|
||||
@item -O @var{file}
|
||||
@itemx --output-document=@var{file}
|
||||
The documents will not be written to the appropriate files, but all
|
||||
@@ -631,6 +651,13 @@ Note that when @samp{-nc} is specified, files with the suffixes
|
||||
@samp{.html} or @samp{.htm} will be loaded from the local disk and
|
||||
parsed as if they had been retrieved from the Web.
|
||||
|
||||
@cindex backing up files
|
||||
@item --backups=@var{backups}
|
||||
Before (over)writing a file, back up an existing file by adding a
|
||||
@samp{.1} suffix (@samp{_1} on VMS) to the file name. Such backup
|
||||
files are rotated to @samp{.2}, @samp{.3}, and so on, up to
|
||||
@var{backups} (and lost beyond that).
|
||||
|
||||
@cindex continue retrieval
|
||||
@cindex incomplete downloads
|
||||
@cindex resume download
|
||||
@@ -695,6 +722,22 @@ Another instance where you'll get a garbled file if you try to use
|
||||
Note that @samp{-c} only works with @sc{ftp} servers and with @sc{http}
|
||||
servers that support the @code{Range} header.
|
||||
|
||||
@cindex offset
|
||||
@cindex continue retrieval
|
||||
@cindex incomplete downloads
|
||||
@cindex resume download
|
||||
@cindex start position
|
||||
@item --start-pos=@var{OFFSET}
|
||||
Start downloading at zero-based position @var{OFFSET}. Offset may be expressed
|
||||
in bytes, kilobytes with the `k' suffix, or megabytes with the `m' suffix, etc.
|
||||
|
||||
@samp{--start-pos} has higher precedence over @samp{--continue}. When
|
||||
@samp{--start-pos} and @samp{--continue} are both specified, wget will emit a
|
||||
warning then proceed as if @samp{--continue} was absent.
|
||||
|
||||
Server support for continued download is required, otherwise @samp{--start-pos}
|
||||
cannot help. See @samp{-c} for details.
|
||||
|
||||
@cindex progress indicator
|
||||
@cindex dot style
|
||||
@item --progress=@var{type}
|
||||
@@ -710,21 +753,53 @@ Use @samp{--progress=dot} to switch to the ``dot'' display. It traces
|
||||
the retrieval by printing dots on the screen, each dot representing a
|
||||
fixed amount of downloaded data.
|
||||
|
||||
When using the dotted retrieval, you may also set the @dfn{style} by
|
||||
The progress @var{type} can also take one or more parameters. The parameters
|
||||
vary based on the @var{type} selected. Parameters to @var{type} are passed by
|
||||
appending them to the type sperated by a colon (:) like this:
|
||||
@samp{--progress=@var{type}:@var{parameter1}:@var{parameter2}}.
|
||||
|
||||
When using the dotted retrieval, you may set the @dfn{style} by
|
||||
specifying the type as @samp{dot:@var{style}}. Different styles assign
|
||||
different meaning to one dot. With the @code{default} style each dot
|
||||
represents 1K, there are ten dots in a cluster and 50 dots in a line.
|
||||
The @code{binary} style has a more ``computer''-like orientation---8K
|
||||
dots, 16-dots clusters and 48 dots per line (which makes for 384K
|
||||
lines). The @code{mega} style is suitable for downloading very large
|
||||
lines). The @code{mega} style is suitable for downloading large
|
||||
files---each dot represents 64K retrieved, there are eight dots in a
|
||||
cluster, and 48 dots on each line (so each line contains 3M).
|
||||
If @code{mega} is not enough then you can use the @code{giga}
|
||||
style---each dot represents 1M retrieved, there are eight dots in a
|
||||
cluster, and 32 dots on each line (so each line contains 32M).
|
||||
|
||||
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
|
||||
behaviour can be overridden and the ``bar'' output forced by using the ``force''
|
||||
parameter as @samp{--progress=bar:force}.
|
||||
|
||||
By default, the @samp{bar} style progress bar scroll the name of the file from
|
||||
left to right for the file being downloaded if the filename exceeds the maximum
|
||||
length allotted for its display. In certain cases, such as with
|
||||
@samp{--progress=bar:force}, one may not want the scrolling filename in the
|
||||
progress bar. By passing the ``noscroll'' parameter, Wget can be forced to
|
||||
display as much of the filename as possible without scrolling through it.
|
||||
|
||||
Note that you can set the default style using the @code{progress}
|
||||
command in @file{.wgetrc}. That setting may be overridden from the
|
||||
command line. The exception is that, when the output is not a TTY, the
|
||||
``dot'' progress will be favored over ``bar''. To force the bar output,
|
||||
use @samp{--progress=bar:force}.
|
||||
command line. For example, to force the bar output without scrolling,
|
||||
use @samp{--progress=bar:force:noscroll}.
|
||||
|
||||
@item --show-progress
|
||||
Force wget to display the progress bar in any verbosity.
|
||||
|
||||
By default, wget only displays the progress bar in verbose mode. One may
|
||||
however want wget to display the progress bar on screen in conjunction with
|
||||
any other verbosity modes like @samp{--no-verbose} or @samp{--quiet}. This
|
||||
is often a desired a property when invoking wget to download several small/large
|
||||
files. In such a case, wget could simply be invoked with this parameter to get
|
||||
a much cleaner output on the screen.
|
||||
|
||||
@item -N
|
||||
@itemx --timestamping
|
||||
@@ -733,7 +808,7 @@ Turn on time-stamping. @xref{Time-Stamping}, for details.
|
||||
@item --no-use-server-timestamps
|
||||
Don't set the local file's timestamp by the one on the server.
|
||||
|
||||
By default, when a file is downloaded, it's timestamps are set to
|
||||
By default, when a file is downloaded, its timestamps are set to
|
||||
match those from the remote file. This allows the use of
|
||||
@samp{--timestamping} on subsequent invocations of wget. However, it
|
||||
is sometimes useful to base the local file's timestamp on when it was
|
||||
@@ -876,12 +951,13 @@ recommendation to block many unrelated users from a web site due to the
|
||||
actions of one.
|
||||
|
||||
@cindex proxy
|
||||
@itemx --no-proxy
|
||||
@item --no-proxy
|
||||
Don't use proxies, even if the appropriate @code{*_proxy} environment
|
||||
variable is defined.
|
||||
|
||||
@c man end
|
||||
For more information about the use of proxies with Wget, @xref{Proxies}.
|
||||
@xref{Proxies}, for more information about the use of proxies with
|
||||
Wget.
|
||||
@c man begin OPTIONS
|
||||
|
||||
@cindex quota
|
||||
@@ -977,7 +1053,7 @@ are outside the range of @sc{ascii} characters (that is, greater than
|
||||
whose encoding does not match the one used locally.
|
||||
|
||||
@cindex IPv6
|
||||
@itemx -4
|
||||
@item -4
|
||||
@itemx --inet4-only
|
||||
@itemx -6
|
||||
@itemx --inet6-only
|
||||
@@ -1090,6 +1166,14 @@ command line.
|
||||
Force Wget to unlink file instead of clobbering existing file. This
|
||||
option is useful for downloading to the directory with hardlinks.
|
||||
|
||||
@cindex jobs
|
||||
@item --jobs=@var{number}
|
||||
|
||||
Specify the @var{number} of threads to use. Unless specified, the number of
|
||||
threads used is 1.
|
||||
|
||||
Currently this option works only for recursive downloading and when specified with
|
||||
option @samp{--metalink}.
|
||||
@end table
|
||||
|
||||
@node Directory Options, HTTP Options, Download Options, Invoking
|
||||
@@ -1223,8 +1307,8 @@ really important, do not leave them lying in those files either---edit
|
||||
the files and delete them after Wget has started the download.
|
||||
|
||||
@iftex
|
||||
For more information about security issues with Wget, @xref{Security
|
||||
Considerations}.
|
||||
@xref{Security Considerations}, for more information about security
|
||||
issues with Wget.
|
||||
@end iftex
|
||||
|
||||
@cindex Keep-Alive, turning off
|
||||
@@ -1458,6 +1542,11 @@ like everything else. Wget does not currently support
|
||||
@code{application/x-www-form-urlencoded}. Only one of
|
||||
@samp{--post-data} and @samp{--post-file} should be specified.
|
||||
|
||||
Please note that wget does not require the content to be of the form
|
||||
@code{key1=value1&key2=value2}, and neither does it test for it. Wget will
|
||||
simply transmit whatever data is provided to it. Most servers however expect
|
||||
the POST data to be in the above format when processing HTML Forms.
|
||||
|
||||
Please be aware that Wget needs to know the size of the POST data in
|
||||
advance. Therefore the argument to @code{--post-file} must be a regular
|
||||
file; specifying a FIFO or something like @file{/dev/stdin} won't work.
|
||||
@@ -1468,14 +1557,15 @@ use chunked unless it knows it's talking to an HTTP/1.1 server. And it
|
||||
can't know that until it receives a response, which in turn requires the
|
||||
request to have been completed -- a chicken-and-egg problem.
|
||||
|
||||
Note: if Wget is redirected after the POST request is completed, it
|
||||
will not send the POST data to the redirected URL. This is because
|
||||
URLs that process POST often respond with a redirection to a regular
|
||||
page, which does not desire or accept POST. It is not completely
|
||||
clear that this behavior is optimal; if it doesn't work out, it might
|
||||
be changed in the future.
|
||||
Note: As of version 1.15 if Wget is redirected after the POST request is
|
||||
completed, its behaviour will depend on the response code returned by the
|
||||
server. In case of a 301 Moved Permanently, 302 Moved Temporarily or
|
||||
307 Temporary Redirect, Wget will, in accordance with RFC2616, continue
|
||||
to send a POST request.
|
||||
In case a server wants the client to change the Request method upon
|
||||
redirection, it should send a 303 See Other response code.
|
||||
|
||||
This example shows how to log to a server using POST and then proceed to
|
||||
This example shows how to log in to a server using POST and then proceed to
|
||||
download the desired pages, presumably only accessible to authorized
|
||||
users:
|
||||
|
||||
@@ -1498,6 +1588,37 @@ them (and neither will browsers) and the @file{cookies.txt} file will
|
||||
be empty. In that case use @samp{--keep-session-cookies} along with
|
||||
@samp{--save-cookies} to force saving of session cookies.
|
||||
|
||||
@cindex Other HTTP Methods
|
||||
@item --method=@var{HTTP-Method}
|
||||
For the purpose of RESTful scripting, Wget allows sending of other HTTP Methods
|
||||
without the need to explicitly set them using @samp{--header=Header-Line}.
|
||||
Wget will use whatever string is passed to it after @samp{--method} as the HTTP
|
||||
Method to the server.
|
||||
|
||||
@item --body-data=@var{Data-String}
|
||||
@itemx --body-file=@var{Data-File}
|
||||
Must be set when additional data needs to be sent to the server along with the
|
||||
Method specified using @samp{--method}. @samp{--body-data} sends @var{string} as
|
||||
data, whereas @samp{--body-file} sends the contents of @var{file}. Other than that,
|
||||
they work in exactly the same way.
|
||||
|
||||
Currently, @samp{--body-file} is @emph{not} for transmitting files as a whole.
|
||||
Wget does not currently support @code{multipart/form-data} for transmitting data;
|
||||
only @code{application/x-www-form-urlencoded}. In the future, this may be changed
|
||||
so that wget sends the @samp{--body-file} as a complete file instead of sending its
|
||||
contents to the server. Please be aware that Wget needs to know the contents of
|
||||
BODY Data in advance, and hence the argument to @samp{--body-file} should be a
|
||||
regular file. See @samp{--post-file} for a more detailed explanation.
|
||||
Only one of @samp{--body-data} and @samp{--body-file} should be specified.
|
||||
|
||||
If Wget is redirected after the request is completed, Wget will
|
||||
suspend the current method and send a GET request till the redirection
|
||||
is completed. This is true for all redirection response codes except
|
||||
307 Temporary Redirect which is used to explicitly specify that the
|
||||
request method should @emph{not} change. Another exception is when
|
||||
the method is set to @code{POST}, in which case the redirection rules
|
||||
specified under @samp{--post-data} are followed.
|
||||
|
||||
@cindex Content-Disposition
|
||||
@item --content-disposition
|
||||
|
||||
@@ -1549,16 +1670,24 @@ without SSL support, none of these options are available.
|
||||
@cindex SSL protocol, choose
|
||||
@item --secure-protocol=@var{protocol}
|
||||
Choose the secure protocol to be used. Legal values are @samp{auto},
|
||||
@samp{SSLv2}, @samp{SSLv3}, and @samp{TLSv1}. If @samp{auto} is used,
|
||||
the SSL library is given the liberty of choosing the appropriate
|
||||
@samp{SSLv2}, @samp{SSLv3}, @samp{TLSv1} and @samp{PFS}. If @samp{auto}
|
||||
is used, the SSL library is given the liberty of choosing the appropriate
|
||||
protocol automatically, which is achieved by sending an SSLv2 greeting
|
||||
and announcing support for SSLv3 and TLSv1. This is the default.
|
||||
|
||||
Specifying @samp{SSLv2}, @samp{SSLv3}, or @samp{TLSv1} forces the use
|
||||
of the corresponding protocol. This is useful when talking to old and
|
||||
buggy SSL server implementations that make it hard for OpenSSL to
|
||||
choose the correct protocol version. Fortunately, such servers are
|
||||
quite rare.
|
||||
buggy SSL server implementations that make it hard for the underlying
|
||||
SSL library to choose the correct protocol version. Fortunately, such
|
||||
servers are quite rare.
|
||||
|
||||
Specifying @samp{PFS} enforces the use of the so-called Perfect Forward
|
||||
Security cipher suites. In short, PFS adds security by creating a one-time
|
||||
key for each SSL connection. It has a bit more CPU impact on client and server.
|
||||
We use known to be secure ciphers (e.g. no MD4) and the TLS protocol.
|
||||
|
||||
@item --https-only
|
||||
When in recursive mode, only HTTPS links are followed.
|
||||
|
||||
@cindex SSL certificate, check
|
||||
@item --no-check-certificate
|
||||
@@ -1715,8 +1844,8 @@ really important, do not leave them lying in those files either---edit
|
||||
the files and delete them after Wget has started the download.
|
||||
|
||||
@iftex
|
||||
For more information about security issues with Wget, @xref{Security
|
||||
Considerations}.
|
||||
@xref{Security Considerations}, for more information about security
|
||||
issues with Wget.
|
||||
@end iftex
|
||||
|
||||
@cindex .listing files, removing
|
||||
@@ -1777,6 +1906,10 @@ in some rare firewall configurations, active FTP actually works when
|
||||
passive FTP doesn't. If you suspect this to be the case, use this
|
||||
option, or set @code{passive_ftp=off} in your init file.
|
||||
|
||||
@cindex file permissions
|
||||
@item --preserve-permissions
|
||||
Preserve remote file permissions instead of permissions set by umask.
|
||||
|
||||
@cindex symbolic links, retrieving
|
||||
@item --retr-symlinks
|
||||
Usually, when retrieving @sc{ftp} directories recursively and a symbolic
|
||||
@@ -2013,6 +2146,17 @@ accept or reject (@pxref{Types of Files}). Note that if
|
||||
any of the wildcard characters, @samp{*}, @samp{?}, @samp{[} or
|
||||
@samp{]}, appear in an element of @var{acclist} or @var{rejlist},
|
||||
it will be treated as a pattern, rather than a suffix.
|
||||
In this case, you have to enclose the pattern into quotes to prevent
|
||||
your shell from expanding it, like in @samp{-A "*.mp3"} or @samp{-A '*.mp3'}.
|
||||
|
||||
@item --accept-regex @var{urlregex}
|
||||
@itemx --reject-regex @var{urlregex}
|
||||
Specify a regular expression to accept or reject the complete URL.
|
||||
|
||||
@item --regex-type @var{regextype}
|
||||
Specify the regular expression type. Possible types are @samp{posix} or
|
||||
@samp{pcre}. Note that to be able to use @samp{pcre} type, wget has to be
|
||||
compiled with libpcre support.
|
||||
|
||||
@item -D @var{domain-list}
|
||||
@itemx --domains=@var{domain-list}
|
||||
@@ -2061,8 +2205,10 @@ dedicated @samp{--page-requisites} option.
|
||||
Ignore case when matching files and directories. This influences the
|
||||
behavior of -R, -A, -I, and -X options, as well as globbing
|
||||
implemented when downloading from FTP sites. For example, with this
|
||||
option, @samp{-A *.txt} will match @samp{file1.txt}, but also
|
||||
option, @samp{-A "*.txt"} will match @samp{file1.txt}, but also
|
||||
@samp{file2.TXT}, @samp{file3.TxT}, and so on.
|
||||
The quotes in the example are to prevent the shell from expanding the
|
||||
pattern.
|
||||
|
||||
@item -H
|
||||
@itemx --span-hosts
|
||||
@@ -2830,9 +2976,11 @@ enables it).
|
||||
Enable/disable saving pre-converted files with the suffix
|
||||
@samp{.orig}---the same as @samp{-K} (which enables it).
|
||||
|
||||
@c @item backups = @var{number}
|
||||
@c #### Document me!
|
||||
@c
|
||||
@item backups = @var{number}
|
||||
Use up to @var{number} backups for a file. Backups are rotated by
|
||||
adding an incremental counter that starts at @samp{1}. The default is
|
||||
@samp{0}.
|
||||
|
||||
@item base = @var{string}
|
||||
Consider relative @sc{url}s in input files (specified via the
|
||||
@samp{input} command or the @samp{--input-file}/@samp{-i} option,
|
||||
@@ -3094,7 +3242,7 @@ display properly---the same as @samp{-p}.
|
||||
Change setting of passive @sc{ftp}, equivalent to the
|
||||
@samp{--passive-ftp} option.
|
||||
|
||||
@itemx password = @var{string}
|
||||
@item password = @var{string}
|
||||
Specify password @var{string} for both @sc{ftp} and @sc{http} file retrieval.
|
||||
This command can be overridden using the @samp{ftp_password} and
|
||||
@samp{http_password} command for @sc{ftp} and @sc{http} respectively.
|
||||
@@ -3605,7 +3753,7 @@ In addition to the environment variables, proxy location and settings
|
||||
may be specified from within Wget itself.
|
||||
|
||||
@table @samp
|
||||
@itemx --no-proxy
|
||||
@item --no-proxy
|
||||
@itemx proxy = on/off
|
||||
This option and the corresponding command may be used to suppress the
|
||||
use of proxy, even if the appropriate environment variables are set.
|
||||
@@ -4317,7 +4465,7 @@ subscribers of the Wget mailing list.
|
||||
@appendix Copying this manual
|
||||
|
||||
@menu
|
||||
* GNU Free Documentation License:: Licnse for copying this manual.
|
||||
* GNU Free Documentation License:: License for copying this manual.
|
||||
@end menu
|
||||
|
||||
@node GNU Free Documentation License, , Copying this manual, Copying this manual
|
||||
|
||||
1
gnulib
Submodule
1
gnulib
Submodule
Submodule gnulib added at 98ca2c063c
@@ -51,8 +51,8 @@ dnl /usr/local/include (!), which GCC uses before /usr/include.
|
||||
|
||||
AC_DEFUN([WGET_FNMATCH], [
|
||||
AC_MSG_CHECKING([for working fnmatch.h])
|
||||
AC_COMPILE_IFELSE([#include <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.])
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
2014-06-11 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.DJ: Remove terminating empty lines.
|
||||
* Makefile.WC: Likewise.
|
||||
* msdos.c: Likewise.
|
||||
|
||||
2009-09-06 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* Makefile.WC: Added compilation of new file msdos.c.
|
||||
|
||||
@@ -87,4 +87,3 @@ depend: version.c
|
||||
sed -e 's/^\([a-zA-Z0-9_-]*\.o:\)/$$(OBJ_DIR)\/\1/' > depend.dj
|
||||
|
||||
-include depend.dj
|
||||
|
||||
|
||||
@@ -65,4 +65,3 @@ version.c: ..\msdos\Makefile.WC
|
||||
clean: .SYMBOLIC
|
||||
- rm $(OBJ_DIR)\*.obj wget.exe wget.map version.c css.c
|
||||
- rmdir $(OBJ_DIR)
|
||||
|
||||
|
||||
@@ -105,4 +105,3 @@ getpass (const char *prompt)
|
||||
|
||||
return strdup (getpassbuf);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,13 @@
|
||||
|
||||
# Package source files
|
||||
lib/error.c
|
||||
lib/gai_strerror.c
|
||||
lib/getopt.c
|
||||
lib/quotearg.c
|
||||
lib/regcomp.c
|
||||
lib/spawn-pipe.c
|
||||
lib/w32spawn.h
|
||||
lib/wait-process.c
|
||||
lib/xalloc-die.c
|
||||
src/connect.c
|
||||
src/convert.c
|
||||
@@ -32,3 +37,4 @@ src/retr.c
|
||||
src/spider.c
|
||||
src/url.c
|
||||
src/utils.c
|
||||
src/warc.c
|
||||
|
||||
1610
src/ChangeLog
1610
src/ChangeLog
File diff suppressed because it is too large
Load Diff
@@ -56,4 +56,3 @@ MODS_OBJS_LIB_SRC_SSL =
|
||||
.ENDIF # CDEFS_SSL [else]
|
||||
|
||||
MODS_OBJS_LIB_SRC = $(MODS_OBJS_LIB_SRC_NOSSL) $(MODS_OBJS_LIB_SRC_SSL)
|
||||
|
||||
|
||||
@@ -32,4 +32,3 @@ CFLAGS_SPEC = /prefix_library_entries = \
|
||||
# Object library modules.
|
||||
|
||||
.INCLUDE DESCRIP_MODS.MMS
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for `wget' utility
|
||||
# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
||||
# 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
||||
# 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,35 +28,50 @@
|
||||
# as that of the covered work.
|
||||
|
||||
#
|
||||
# Version: @VERSION@
|
||||
# Version: $(VERSION)
|
||||
#
|
||||
|
||||
if IRI_IS_ENABLED
|
||||
IRI_OBJ = iri.c
|
||||
endif
|
||||
if METALINK_IS_ENABLED
|
||||
METALINK_OBJ = metalink.c
|
||||
METALINK_HEADER = metalink.h
|
||||
endif
|
||||
if THREADS_ARE_ENABLED
|
||||
THREAD_OBJ = multi.c
|
||||
MULTI_HEADER = multi.h
|
||||
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)
|
||||
DEFS += -DSYSTEM_WGETRC=\"$(sysconfdir)/wgetrc\" -DLOCALEDIR=\"$(localedir)\"
|
||||
LIBS += $(LIBICONV) $(LIBINTL) $(LIB_CLOCK_GETTIME)
|
||||
|
||||
EXTRA_DIST = css.l css.c css_.c build_info.c.in
|
||||
EXTRA_DIST = css.l css.c css_.c build_info.c.in iri.c multi.c multi.h metalink.c metalink.h
|
||||
|
||||
bin_PROGRAMS = wget
|
||||
wget_SOURCES = cmpt.c connect.c convert.c cookies.c ftp.c \
|
||||
css_.c css-url.c \
|
||||
ftp-basic.c ftp-ls.c hash.c host.c html-parse.c html-url.c \
|
||||
http.c init.c log.c main.c netrc.c progress.c ptimer.c \
|
||||
recur.c res.c retr.c spider.c url.c warc.c \
|
||||
utils.c exits.c build_info.c $(IRI_OBJ) \
|
||||
css-url.h css-tokens.h connect.h convert.h cookies.h \
|
||||
ftp.h hash.h host.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 gettext.h
|
||||
|
||||
wget_SOURCES = cmpt.c connect.c convert.c cookies.c ftp.c \
|
||||
css_.c css-url.c \
|
||||
ftp-basic.c ftp-ls.c hash.c host.c html-parse.c html-url.c \
|
||||
http.c init.c log.c main.c netrc.c progress.c ptimer.c \
|
||||
recur.c res.c retr.c spider.c url.c warc.c \
|
||||
utils.c exits.c build_info.c $(IRI_OBJ) \
|
||||
$(THREAD_OBJ) $(METALINK_OBJ) \
|
||||
css-url.h css-tokens.h connect.h convert.h cookies.h \
|
||||
ftp.h hash.h host.h html-parse.h html-url.h \
|
||||
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 gettext.h $(THREAD_HEADER) $(METALINK_HEADER)
|
||||
|
||||
am__wget_SOURCES_DIST = $(wget_SOURCES)
|
||||
am__libunittest_a_SOURCES_DIST = $(wget_SOURCES)
|
||||
|
||||
|
||||
nodist_wget_SOURCES = version.c
|
||||
EXTRA_wget_SOURCES = iri.c
|
||||
LDADD = $(LIBOBJS) ../lib/libgnu.a
|
||||
AM_LDFLAGS = $(THREAD_LIB)
|
||||
AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib
|
||||
|
||||
|
||||
@@ -74,7 +89,7 @@ version.c: $(wget_SOURCES) ../lib/libgnu.a
|
||||
echo '/* version.c */' > $@
|
||||
echo '/* Autogenerated by Makefile - DO NOT EDIT */' >> $@
|
||||
echo '' >> $@
|
||||
echo 'const char *version_string = "@VERSION@";' >> $@
|
||||
echo 'const char *version_string = "$(VERSION)";' >> $@
|
||||
echo 'const char *compilation_string = "'$(COMPILE)'";' \
|
||||
| $(ESCAPEQUOTE) >> $@
|
||||
echo 'const char *link_string = "'$(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
|
||||
@@ -7,6 +7,9 @@ large-file SIZEOF_OFF_T >= 8
|
||||
nls defined ENABLE_NLS
|
||||
ntlm defined ENABLE_NTLM
|
||||
opie defined ENABLE_OPIE
|
||||
threads defined ENABLE_THREADS
|
||||
metalink defined ENABLE_METALINK
|
||||
psl defined HAVE_LIBPSL
|
||||
|
||||
ssl choice:
|
||||
openssl defined HAVE_LIBSSL || defined HAVE_LIBSSL32
|
||||
|
||||
@@ -372,7 +372,7 @@ static void
|
||||
day_of_the_week (struct tm *tm)
|
||||
{
|
||||
/* We know that January 1st 1970 was a Thursday (= 4). Compute the
|
||||
the difference between this data in the one on TM and so determine
|
||||
difference between this data in the one on TM and so determine
|
||||
the weekday. */
|
||||
int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
|
||||
int wday = (-473
|
||||
|
||||
@@ -59,10 +59,7 @@ as that of the covered work. */
|
||||
#include "connect.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Apparently needed for Interix: */
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
/* Define sockaddr_storage where unavailable (presumably on IPv4-only
|
||||
hosts). */
|
||||
@@ -273,7 +270,7 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
|
||||
const char *txt_addr = print_address (ip);
|
||||
if (0 != strcmp (print, txt_addr))
|
||||
{
|
||||
char *str = NULL, *name;
|
||||
char *str = NULL, *name;
|
||||
|
||||
if (opt.enable_iri && (name = idn_decode ((char *) print)) != NULL)
|
||||
{
|
||||
@@ -287,16 +284,18 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
|
||||
logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "),
|
||||
str ? str : escnonprint_uri (print), txt_addr, port);
|
||||
|
||||
if (str)
|
||||
xfree (str);
|
||||
if (str)
|
||||
xfree (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if (ip->family == AF_INET)
|
||||
logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port);
|
||||
#ifdef ENABLE_IPV6
|
||||
else if (ip->family == AF_INET6)
|
||||
logprintf (LOG_VERBOSE, _("Connecting to [%s]:%d... "), txt_addr, port);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Store the sockaddr info to SA. */
|
||||
@@ -557,6 +556,7 @@ socket_ip_address (int sock, ip_address *ip, int endpoint)
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
memset(ip, 0, sizeof(ip_address));
|
||||
ip->family = sockaddr->sa_family;
|
||||
switch (sockaddr->sa_family)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ as that of the covered work. */
|
||||
#ifndef CONNECT_H
|
||||
#define CONNECT_H
|
||||
|
||||
#include "host.h" /* for definition of ip_address */
|
||||
#include "host.h" /* for definition of ip_address */
|
||||
|
||||
/* Function declarations */
|
||||
|
||||
@@ -60,7 +60,11 @@ enum {
|
||||
WAIT_FOR_READ = 1,
|
||||
WAIT_FOR_WRITE = 2
|
||||
};
|
||||
#ifdef ENABLE_THREADS
|
||||
int select_fds (int *, int *, int, double, int);
|
||||
#else
|
||||
int select_fd (int, double, int);
|
||||
#endif
|
||||
bool test_socket_open (int);
|
||||
|
||||
struct transport_implementation {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Conversion of links to local files.
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -36,6 +36,9 @@ as that of the covered work. */
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include "convert.h"
|
||||
#include "url.h"
|
||||
#include "recur.h"
|
||||
@@ -55,6 +58,49 @@ struct hash_table *dl_url_file_map;
|
||||
struct hash_table *downloaded_html_set;
|
||||
struct hash_table *downloaded_css_set;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
static pthread_mutex_t convert_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void
|
||||
lock_convert_mutex()
|
||||
{
|
||||
static int convert_mutex_init_p = 0;
|
||||
if (! convert_mutex_init_p)
|
||||
{
|
||||
pthread_mutexattr_t mta;
|
||||
pthread_mutexattr_init (&mta);
|
||||
pthread_mutexattr_settype (&mta, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
pthread_mutex_init (&convert_mutex, &mta);
|
||||
convert_mutex_init_p = 1;
|
||||
}
|
||||
pthread_mutex_lock (&convert_mutex);
|
||||
}
|
||||
|
||||
|
||||
#define THREAD_SAFE(ret, fn, args, argv) \
|
||||
ret fn args \
|
||||
{ \
|
||||
ret r; \
|
||||
lock_convert_mutex(); \
|
||||
r = fn##_1 argv; \
|
||||
pthread_mutex_unlock (&convert_mutex); \
|
||||
return r; \
|
||||
}
|
||||
|
||||
#define THREAD_SAFE_VOID(fn, args, argv) \
|
||||
void fn args \
|
||||
{ \
|
||||
lock_convert_mutex(); \
|
||||
fn##_1 argv; \
|
||||
pthread_mutex_unlock (&convert_mutex); \
|
||||
}
|
||||
|
||||
#define FNNAME_WTHREADS(fn) fn##_1
|
||||
#else
|
||||
#define FNNAME_WTHREADS(fn) fn
|
||||
#endif
|
||||
|
||||
static void convert_links (const char *, struct urlpos *);
|
||||
|
||||
|
||||
@@ -125,7 +171,7 @@ convert_links_in_hashtable (struct hash_table *downloaded_set,
|
||||
|
||||
u = url_parse (cur_url->url->url, NULL, pi, true);
|
||||
if (!u)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
local_name = hash_table_get (dl_url_file_map, u->url);
|
||||
|
||||
@@ -182,7 +228,7 @@ convert_links_in_hashtable (struct hash_table *downloaded_set,
|
||||
extracted from these two lists. */
|
||||
|
||||
void
|
||||
convert_all_links (void)
|
||||
FNNAME_WTHREADS(convert_all_links) (void)
|
||||
{
|
||||
double secs;
|
||||
int file_count = 0;
|
||||
@@ -465,7 +511,7 @@ write_backup_file (const char *file, downloaded_file_t downloaded_file_return)
|
||||
converted_files = make_string_hash_table (0);
|
||||
|
||||
/* We can get called twice on the same URL thanks to the
|
||||
convert_all_links() call in main(). If we write the .orig file
|
||||
convert_all_links() call in main. If we write the .orig file
|
||||
each time in such a case, it'll end up containing the first-pass
|
||||
conversion, not the original file. So, see if we've already been
|
||||
called on this file. */
|
||||
@@ -626,6 +672,7 @@ local_quote_string (const char *file, bool no_html_quote)
|
||||
/* Allocate space assuming the worst-case scenario, each character
|
||||
having to be quoted. */
|
||||
to = newname = (char *)alloca (3 * strlen (file) + 1);
|
||||
newname[0] = '\0';
|
||||
for (from = file; *from; from++)
|
||||
switch (*from)
|
||||
{
|
||||
@@ -760,7 +807,7 @@ dissociate_urls_from_file (const char *file)
|
||||
URL has already been downloaded. */
|
||||
|
||||
void
|
||||
register_download (const char *url, const char *file)
|
||||
FNNAME_WTHREADS(register_download) (const char *url, const char *file)
|
||||
{
|
||||
char *old_file, *old_url;
|
||||
|
||||
@@ -835,12 +882,12 @@ register_download (const char *url, const char *file)
|
||||
hash_table_put (dl_url_file_map, xstrdup (url), xstrdup (file));
|
||||
}
|
||||
|
||||
/* Register that FROM has been redirected to TO. This assumes that TO
|
||||
/* Register that FROM has been redirected to "TO". This assumes that TO
|
||||
is successfully downloaded and already registered using
|
||||
register_download() above. */
|
||||
|
||||
void
|
||||
register_redirection (const char *from, const char *to)
|
||||
FNNAME_WTHREADS(register_redirection) (const char *from, const char *to)
|
||||
{
|
||||
char *file;
|
||||
|
||||
@@ -855,7 +902,7 @@ register_redirection (const char *from, const char *to)
|
||||
/* Register that the file has been deleted. */
|
||||
|
||||
void
|
||||
register_delete_file (const char *file)
|
||||
FNNAME_WTHREADS(register_delete_file) (const char *file)
|
||||
{
|
||||
char *old_url, *old_file;
|
||||
|
||||
@@ -873,7 +920,7 @@ register_delete_file (const char *file)
|
||||
/* Register that FILE is an HTML file that has been downloaded. */
|
||||
|
||||
void
|
||||
register_html (const char *file)
|
||||
FNNAME_WTHREADS(register_html) (const char *url, const char *file)
|
||||
{
|
||||
if (!downloaded_html_set)
|
||||
downloaded_html_set = make_string_hash_table (0);
|
||||
@@ -883,7 +930,7 @@ register_html (const char *file)
|
||||
/* Register that FILE is a CSS file that has been downloaded. */
|
||||
|
||||
void
|
||||
register_css (const char *file)
|
||||
FNNAME_WTHREADS(register_css) (const char *url, const char *file)
|
||||
{
|
||||
if (!downloaded_css_set)
|
||||
downloaded_css_set = make_string_hash_table (0);
|
||||
@@ -894,8 +941,8 @@ static void downloaded_files_free (void);
|
||||
|
||||
/* Cleanup the data structures associated with this file. */
|
||||
|
||||
void
|
||||
convert_cleanup (void)
|
||||
static void
|
||||
FNNAME_WTHREADS(convert_cleanup) (void)
|
||||
{
|
||||
if (dl_file_url_map)
|
||||
{
|
||||
@@ -970,7 +1017,7 @@ downloaded_mode_to_ptr (downloaded_file_t mode)
|
||||
URLs. */
|
||||
|
||||
downloaded_file_t
|
||||
downloaded_file (downloaded_file_t mode, const char *file)
|
||||
FNNAME_WTHREADS(downloaded_file) (downloaded_file_t mode, const char *file)
|
||||
{
|
||||
downloaded_file_t *ptr;
|
||||
|
||||
@@ -1084,7 +1131,17 @@ html_quote_string (const char *s)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
THREAD_SAFE (downloaded_file_t, downloaded_file, (downloaded_file_t a, const char *b), (a, b));
|
||||
THREAD_SAFE_VOID (register_download, (const char *a, const char *b), (a, b));
|
||||
THREAD_SAFE_VOID (register_redirection, (const char *a, const char *b), (a, b));
|
||||
THREAD_SAFE_VOID (register_html, (const char *a, const char *b), (a, b));
|
||||
THREAD_SAFE_VOID (register_css, (const char *a, const char *b), (a, b));
|
||||
THREAD_SAFE_VOID (register_delete_file, (const char *a), (a));
|
||||
THREAD_SAFE_VOID (convert_cleanup, (void), ());
|
||||
THREAD_SAFE_VOID (convert_all_links, (void), ());
|
||||
#endif
|
||||
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
@@ -31,18 +31,18 @@ as that of the covered work. */
|
||||
#ifndef CONVERT_H
|
||||
#define CONVERT_H
|
||||
|
||||
struct hash_table; /* forward decl */
|
||||
struct hash_table; /* forward decl */
|
||||
extern struct hash_table *dl_url_file_map;
|
||||
extern struct hash_table *downloaded_html_set;
|
||||
extern struct hash_table *downloaded_css_set;
|
||||
|
||||
enum convert_options {
|
||||
CO_NOCONVERT = 0, /* don't convert this URL */
|
||||
CO_CONVERT_TO_RELATIVE, /* convert to relative, e.g. to
|
||||
CO_NOCONVERT = 0, /* don't convert this URL */
|
||||
CO_CONVERT_TO_RELATIVE, /* convert to relative, e.g. to
|
||||
"../../otherdir/foo.gif" */
|
||||
CO_CONVERT_TO_COMPLETE, /* convert to absolute, e.g. to
|
||||
"http://orighost/somedir/bar.jpg". */
|
||||
CO_NULLIFY_BASE /* change to empty string. */
|
||||
CO_CONVERT_TO_COMPLETE, /* convert to absolute, e.g. to
|
||||
"http://orighost/somedir/bar.jpg". */
|
||||
CO_NULLIFY_BASE /* change to empty string. */
|
||||
};
|
||||
|
||||
struct url;
|
||||
@@ -51,36 +51,36 @@ struct url;
|
||||
position in an HTML document, etc. */
|
||||
|
||||
struct urlpos {
|
||||
struct url *url; /* the URL of the link, after it has
|
||||
been merged with the base */
|
||||
char *local_name; /* local file to which it was saved
|
||||
(used by convert_links) */
|
||||
struct url *url; /* the URL of the link, after it has
|
||||
been merged with the base */
|
||||
char *local_name; /* local file to which it was saved
|
||||
(used by convert_links) */
|
||||
|
||||
/* reserved for special links such as <base href="..."> which are
|
||||
used when converting links, but ignored when downloading. */
|
||||
unsigned int ignore_when_downloading :1;
|
||||
unsigned int ignore_when_downloading :1;
|
||||
|
||||
/* Information about the original link: */
|
||||
|
||||
unsigned int link_relative_p :1; /* the link was relative */
|
||||
unsigned int link_complete_p :1; /* the link was complete (had host name) */
|
||||
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_expect_html :1; /* expected to contain HTML */
|
||||
unsigned int link_expect_css :1; /* expected to contain CSS */
|
||||
unsigned int link_relative_p :1; /* the link was relative */
|
||||
unsigned int link_complete_p :1; /* the link was complete (had host name) */
|
||||
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_expect_html :1; /* expected to contain HTML */
|
||||
unsigned int link_expect_css :1; /* expected to contain CSS */
|
||||
|
||||
unsigned int link_refresh_p :1; /* link was received from
|
||||
<meta http-equiv=refresh content=...> */
|
||||
int refresh_timeout; /* for reconstructing the refresh. */
|
||||
unsigned int link_refresh_p :1; /* link was received from
|
||||
<meta http-equiv=refresh content=...> */
|
||||
int refresh_timeout; /* for reconstructing the refresh. */
|
||||
|
||||
/* Conversion requirements: */
|
||||
enum convert_options convert; /* is conversion required? */
|
||||
enum convert_options convert; /* is conversion required? */
|
||||
|
||||
/* URL's position in the buffer. */
|
||||
int pos, size;
|
||||
|
||||
struct urlpos *next; /* next list element */
|
||||
struct urlpos *next; /* next list element */
|
||||
};
|
||||
|
||||
/* downloaded_file() takes a parameter of this type and returns this type. */
|
||||
@@ -98,14 +98,12 @@ typedef enum
|
||||
} downloaded_file_t;
|
||||
|
||||
downloaded_file_t downloaded_file (downloaded_file_t, const char *);
|
||||
|
||||
void register_download (const char *, const char *);
|
||||
void register_redirection (const char *, const char *);
|
||||
void register_html (const char *);
|
||||
void register_css (const char *);
|
||||
void register_delete_file (const char *);
|
||||
void register_download (const char *a, const char *b);
|
||||
void convert_all_links (void);
|
||||
void convert_cleanup (void);
|
||||
void register_delete_file (const char *a);
|
||||
void register_redirection (const char *a, const char *b);
|
||||
void register_css (const char *a, const char *b);
|
||||
void register_html (const char *a, const char *b);
|
||||
|
||||
char *html_quote_string (const char *);
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ as that of the covered work. */
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#ifdef HAVE_LIBPSL
|
||||
# include <libpsl.h>
|
||||
#endif
|
||||
#include "utils.h"
|
||||
#include "hash.h"
|
||||
#include "cookies.h"
|
||||
@@ -95,7 +98,7 @@ struct cookie {
|
||||
int port; /* port number */
|
||||
char *path; /* path prefix of the cookie */
|
||||
|
||||
unsigned discard_requested :1; /* whether cookie was created to
|
||||
unsigned discard_requested :1;/* whether cookie was created to
|
||||
request discarding another
|
||||
cookie. */
|
||||
|
||||
@@ -346,7 +349,7 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
struct cookie *cookie = cookie_new ();
|
||||
param_token name, value;
|
||||
|
||||
if (!extract_param (&ptr, &name, &value, ';'))
|
||||
if (!extract_param (&ptr, &name, &value, ';', NULL))
|
||||
goto error;
|
||||
if (!value.b)
|
||||
goto error;
|
||||
@@ -360,7 +363,7 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
cookie->attr = strdupdelim (name.b, name.e);
|
||||
cookie->value = strdupdelim (value.b, value.e);
|
||||
|
||||
while (extract_param (&ptr, &name, &value, ';'))
|
||||
while (extract_param (&ptr, &name, &value, ';', NULL))
|
||||
{
|
||||
if (TOKEN_IS (name, "domain"))
|
||||
{
|
||||
@@ -393,7 +396,7 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
|
||||
/* Check if expiration spec is valid.
|
||||
If not, assume default (cookie doesn't expire, but valid only for
|
||||
this session.) */
|
||||
this session.) */
|
||||
expires = http_atotm (value_copy);
|
||||
if (expires != (time_t) -1)
|
||||
{
|
||||
@@ -460,9 +463,9 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
|
||||
|
||||
#define REQUIRE_DIGITS(p) do { \
|
||||
if (!c_isdigit (*p)) \
|
||||
if (!c_isdigit (*p)) \
|
||||
return false; \
|
||||
for (++p; c_isdigit (*p); p++) \
|
||||
for (++p; c_isdigit (*p); p++) \
|
||||
; \
|
||||
} while (0)
|
||||
|
||||
@@ -498,19 +501,61 @@ numeric_address_p (const char *addr)
|
||||
/* Check whether COOKIE_DOMAIN is an appropriate domain for HOST.
|
||||
Originally I tried to make the check compliant with rfc2109, but
|
||||
the sites deviated too often, so I had to fall back to "tail
|
||||
matching", as defined by the original Netscape's cookie spec. */
|
||||
matching", as defined by the original Netscape's cookie spec.
|
||||
|
||||
Wget now uses libpsl to check domain names against a public suffix
|
||||
list to see if they are valid. However, since we don't provide a
|
||||
psl on our own, if libpsl is compiled without a public suffix list,
|
||||
fall back to using the original "tail matching" heuristic. Also if
|
||||
libpsl is unable to convert the domain to lowercase, which means that
|
||||
it doesnt have any runtime conversion support, we again fall back to
|
||||
"tail matching" since libpsl states the results are unpredictable with
|
||||
upper case strings.
|
||||
*/
|
||||
|
||||
static bool
|
||||
check_domain_match (const char *cookie_domain, const char *host)
|
||||
{
|
||||
|
||||
#ifdef HAVE_LIBPSL
|
||||
DEBUGP (("cdm: 1"));
|
||||
char *cookie_domain_lower = NULL;
|
||||
char *host_lower = NULL;
|
||||
const psl_ctx_t *psl;
|
||||
int is_acceptable;
|
||||
|
||||
/* Numeric address requires exact match. It also requires HOST to
|
||||
be an IP address. */
|
||||
if (numeric_address_p (cookie_domain))
|
||||
return 0 == strcmp (cookie_domain, host);
|
||||
if (!(psl = psl_builtin()))
|
||||
{
|
||||
DEBUGP (("\nlibpsl not built with a public suffix list. "
|
||||
"Falling back to simple heuristics.\n"));
|
||||
goto no_psl;
|
||||
}
|
||||
|
||||
DEBUGP ((" 2"));
|
||||
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)
|
||||
{
|
||||
is_acceptable = psl_is_cookie_domain_acceptable (psl, host_lower, cookie_domain_lower);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGP (("libpsl unable to parse domain name. "
|
||||
"Falling back to simple heuristics.\n"));
|
||||
goto no_psl;
|
||||
}
|
||||
|
||||
xfree (cookie_domain_lower);
|
||||
xfree (host_lower);
|
||||
|
||||
return is_acceptable == 1;
|
||||
|
||||
no_psl:
|
||||
/* Cleanup the PSL pointers first */
|
||||
xfree (cookie_domain_lower);
|
||||
xfree (host_lower);
|
||||
#endif
|
||||
|
||||
/* For efficiency make some elementary checks first */
|
||||
DEBUGP (("cdm: 2"));
|
||||
|
||||
/* For the sake of efficiency, check for exact match first. */
|
||||
if (0 == strcasecmp (cookie_domain, host))
|
||||
@@ -673,9 +718,6 @@ cookie_handle_set_cookie (struct cookie_jar *jar,
|
||||
|
||||
if (!cookie->domain)
|
||||
{
|
||||
copy_domain:
|
||||
/* If the domain was not provided, we use the one we're talking
|
||||
to, and set exact match. */
|
||||
cookie->domain = xstrdup (host);
|
||||
cookie->domain_exact = 1;
|
||||
/* Set the port, but only if it's non-default. */
|
||||
@@ -687,11 +729,12 @@ cookie_handle_set_cookie (struct cookie_jar *jar,
|
||||
if (!check_domain_match (cookie->domain, host))
|
||||
{
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Cookie coming from %s attempted to set domain to %s\n"),
|
||||
quotearg_style (escape_quoting_style, host),
|
||||
_("Cookie coming from %s attempted to set domain to "),
|
||||
quotearg_style (escape_quoting_style, host));
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("%s\n"),
|
||||
quotearg_style (escape_quoting_style, cookie->domain));
|
||||
xfree (cookie->domain);
|
||||
goto copy_domain;
|
||||
cookie->discard_requested = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1131,7 +1174,9 @@ domain_port (const char *domain_b, const char *domain_e,
|
||||
void
|
||||
cookie_jar_load (struct cookie_jar *jar, const char *file)
|
||||
{
|
||||
char *line;
|
||||
char *line = NULL;
|
||||
size_t bufsize = 0;
|
||||
|
||||
FILE *fp = fopen (file, "r");
|
||||
if (!fp)
|
||||
{
|
||||
@@ -1139,9 +1184,10 @@ cookie_jar_load (struct cookie_jar *jar, const char *file)
|
||||
quote (file), strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
cookies_now = time (NULL);
|
||||
|
||||
for (; ((line = read_whole_line (fp)) != NULL); xfree (line))
|
||||
while (getline (&line, &bufsize, fp) > 0)
|
||||
{
|
||||
struct cookie *cookie;
|
||||
char *p = line;
|
||||
@@ -1235,6 +1281,8 @@ cookie_jar_load (struct cookie_jar *jar, const char *file)
|
||||
abort_cookie:
|
||||
delete_cookie (cookie);
|
||||
}
|
||||
|
||||
xfree(line);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
@@ -1374,7 +1422,7 @@ test_cookies (void)
|
||||
param_token name, value;
|
||||
const char *ptr = data;
|
||||
int j = 0;
|
||||
while (extract_param (&ptr, &name, &value, ';'))
|
||||
while (extract_param (&ptr, &name, &value, ';', NULL))
|
||||
{
|
||||
char *n = strdupdelim (name.b, name.e);
|
||||
char *v = strdupdelim (value.b, value.e);
|
||||
|
||||
@@ -37,9 +37,9 @@ struct cookie_jar *cookie_jar_new (void);
|
||||
void cookie_jar_delete (struct cookie_jar *);
|
||||
|
||||
void cookie_handle_set_cookie (struct cookie_jar *, const char *, int,
|
||||
const char *, const char *);
|
||||
const char *, const char *);
|
||||
char *cookie_header (struct cookie_jar *, const char *, int,
|
||||
const char *, bool);
|
||||
const char *, bool);
|
||||
|
||||
void cookie_jar_load (struct cookie_jar *, const char *);
|
||||
void cookie_jar_save (struct cookie_jar *, const char *);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Collect URLs from CSS source.
|
||||
Copyright (C) 1998, 2000, 2001, 2002, 2003, 2009, 2010, 2011 Free
|
||||
Copyright (C) 1998, 2000, 2001, 2002, 2003, 2009, 2010, 2011, 2014 Free
|
||||
Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -41,11 +41,7 @@ as that of the covered work. */
|
||||
#include <wget.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@@ -64,41 +60,6 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
extern YY_BUFFER_STATE yy_scan_bytes (const char *bytes,int len );
|
||||
extern int yylex (void);
|
||||
|
||||
#if 1
|
||||
const char *token_names[] = {
|
||||
"CSSEOF",
|
||||
"S",
|
||||
"CDO",
|
||||
"CDC",
|
||||
"INCLUDES",
|
||||
"DASHMATCH",
|
||||
"LBRACE",
|
||||
"PLUS",
|
||||
"GREATER",
|
||||
"COMMA",
|
||||
"STRING",
|
||||
"INVALID",
|
||||
"IDENT",
|
||||
"HASH",
|
||||
"IMPORT_SYM",
|
||||
"PAGE_SYM",
|
||||
"MEDIA_SYM",
|
||||
"CHARSET_SYM",
|
||||
"IMPORTANT_SYM",
|
||||
"EMS",
|
||||
"EXS",
|
||||
"LENGTH",
|
||||
"ANGLE",
|
||||
"TIME",
|
||||
"FREQ",
|
||||
"DIMENSION",
|
||||
"PERCENTAGE",
|
||||
"NUMBER",
|
||||
"URI",
|
||||
"FUNCTION"
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
Given a detected URI token, get only the URI specified within.
|
||||
Also adjust the starting position and length of the string.
|
||||
@@ -111,12 +72,6 @@ const char *token_names[] = {
|
||||
static char *
|
||||
get_uri_string (const char *at, int *pos, int *length)
|
||||
{
|
||||
char *uri;
|
||||
/*char buf[1024];
|
||||
strncpy(buf,at + *pos, *length);
|
||||
buf[*length] = '\0';
|
||||
DEBUGP (("get_uri_string: \"%s\"\n", buf));*/
|
||||
|
||||
if (0 != strncasecmp (at + *pos, "url(", 4))
|
||||
return NULL;
|
||||
|
||||
@@ -142,14 +97,7 @@ get_uri_string (const char *at, int *pos, int *length)
|
||||
*length -= 2;
|
||||
}
|
||||
|
||||
uri = xmalloc (*length + 1);
|
||||
if (uri)
|
||||
{
|
||||
strncpy (uri, at + *pos, *length);
|
||||
uri[*length] = '\0';
|
||||
}
|
||||
|
||||
return uri;
|
||||
return xstrdup (at + *pos);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -161,12 +109,6 @@ get_urls_css (struct map_context *ctx, int offset, int buf_length)
|
||||
int pos, length;
|
||||
char *uri;
|
||||
|
||||
/*
|
||||
strncpy(tmp,ctx->text + offset, buf_length);
|
||||
tmp[buf_length] = '\0';
|
||||
DEBUGP (("get_urls_css: \"%s\"\n", tmp));
|
||||
*/
|
||||
|
||||
/* tell flex to scan from this buffer */
|
||||
yy_scan_bytes (ctx->text + offset, buf_length);
|
||||
|
||||
@@ -200,7 +142,7 @@ get_urls_css (struct map_context *ctx, int offset, int buf_length)
|
||||
pos++;
|
||||
length -= 2;
|
||||
uri = xmalloc (length + 1);
|
||||
strncpy (uri, yytext + 1, length);
|
||||
memcpy (uri, yytext + 1, length);
|
||||
uri[length] = '\0';
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
|
||||
int main( void)
|
||||
{
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
/* Set the current locale. */
|
||||
setlocale (LC_ALL, "");
|
||||
/* Set the text message domain. */
|
||||
bindtextdomain ("wget", LOCALEDIR);
|
||||
textdomain ("wget");
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#ifdef __VMS_VERSION
|
||||
printf( " __VMS_VERSION: >%s<.\n", __VMS_VERSION);
|
||||
#else /* def __VMS_VERSION */
|
||||
|
||||
25
src/exits.c
25
src/exits.c
@@ -20,24 +20,6 @@
|
||||
#include "wget.h"
|
||||
#include "exits.h"
|
||||
|
||||
/* Final exit code possibilities. Exit codes 1 and 2 are reserved
|
||||
* for situations that lead to direct exits from Wget, not using the
|
||||
* value of final_exit_status. */
|
||||
enum
|
||||
{
|
||||
WGET_EXIT_SUCCESS = 0,
|
||||
|
||||
WGET_EXIT_MINIMUM = 3,
|
||||
WGET_EXIT_IO_FAIL = WGET_EXIT_MINIMUM,
|
||||
WGET_EXIT_NETWORK_FAIL = 4,
|
||||
WGET_EXIT_SSL_AUTH_FAIL = 5,
|
||||
WGET_EXIT_SERVER_AUTH_FAIL = 6,
|
||||
WGET_EXIT_PROTOCOL_ERROR = 7,
|
||||
WGET_EXIT_SERVER_ERROR = 8,
|
||||
|
||||
WGET_EXIT_UNKNOWN
|
||||
};
|
||||
|
||||
static int final_exit_status = WGET_EXIT_SUCCESS;
|
||||
|
||||
/* XXX: I don't like that newly-added uerr_t codes will doubtless fall
|
||||
@@ -58,7 +40,7 @@ get_status_for_err (uerr_t err)
|
||||
case RETROK:
|
||||
return WGET_EXIT_SUCCESS;
|
||||
case FOPENERR: case FOPEN_EXCL_ERR: case FWRITEERR: case WRITEFAILED:
|
||||
case UNLINKERR: case CLOSEFAILED:
|
||||
case UNLINKERR: case CLOSEFAILED: case FILEBADFILE:
|
||||
return WGET_EXIT_IO_FAIL;
|
||||
case NOCONERROR: case HOSTERR: case CONSOCKERR: case CONERROR:
|
||||
case CONSSLERR: case CONIMPOSSIBLE: case FTPRERR: case FTPINVPASV:
|
||||
@@ -68,7 +50,7 @@ get_status_for_err (uerr_t err)
|
||||
return WGET_EXIT_SSL_AUTH_FAIL;
|
||||
case FTPLOGINC: case FTPLOGREFUSED: case AUTHFAILED:
|
||||
return WGET_EXIT_SERVER_AUTH_FAIL;
|
||||
case HEOF: case HERR:
|
||||
case HEOF: case HERR: case ATTRMISSING:
|
||||
return WGET_EXIT_PROTOCOL_ERROR;
|
||||
case WRONGCODE: case FTPPORTERR: case FTPSYSERR:
|
||||
case FTPNSFOD: case FTPUNKNOWNTYPE: case FTPSRVERR:
|
||||
@@ -76,7 +58,7 @@ get_status_for_err (uerr_t err)
|
||||
case CONTNOTSUPPORTED: case RANGEERR: case RETRBADPATTERN:
|
||||
case PROXERR:
|
||||
return WGET_EXIT_SERVER_ERROR;
|
||||
case URLERROR: case QUOTEXC: case SSLINITFAILED:
|
||||
case URLERROR: case QUOTEXC: case SSLINITFAILED: case UNKNOWNATTR:
|
||||
default:
|
||||
return WGET_EXIT_UNKNOWN;
|
||||
}
|
||||
@@ -108,4 +90,3 @@ get_exit_status (void)
|
||||
? 1
|
||||
: final_exit_status;
|
||||
}
|
||||
|
||||
|
||||
17
src/exits.h
17
src/exits.h
@@ -21,6 +21,23 @@ along with Wget. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
/* Final exit code possibilities. Exit codes 1 and 2 are reserved
|
||||
* for situations that lead to direct exits from Wget, not using the
|
||||
* value of final_exit_status. */
|
||||
enum
|
||||
{
|
||||
WGET_EXIT_SUCCESS = 0,
|
||||
WGET_EXIT_GENERIC_ERROR = 1,
|
||||
WGET_EXIT_PARSE_ERROR = 2,
|
||||
WGET_EXIT_IO_FAIL = 3,
|
||||
WGET_EXIT_NETWORK_FAIL = 4,
|
||||
WGET_EXIT_SSL_AUTH_FAIL = 5,
|
||||
WGET_EXIT_SERVER_AUTH_FAIL = 6,
|
||||
WGET_EXIT_PROTOCOL_ERROR = 7,
|
||||
WGET_EXIT_SERVER_ERROR = 8,
|
||||
|
||||
WGET_EXIT_UNKNOWN
|
||||
};
|
||||
|
||||
void inform_exit_status (uerr_t err);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Basic FTP routines.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -44,8 +44,6 @@ as that of the covered work. */
|
||||
#include "ftp.h"
|
||||
#include "retr.h"
|
||||
|
||||
char ftp_last_respline[128];
|
||||
|
||||
|
||||
/* Get the response of FTP server and allocate enough room to handle
|
||||
it. <CR> and <LF> characters are stripped from the line, and the
|
||||
@@ -84,8 +82,6 @@ ftp_response (int fd, char **ret_line)
|
||||
if (c_isdigit (line[0]) && c_isdigit (line[1]) && c_isdigit (line[2])
|
||||
&& line[3] == ' ')
|
||||
{
|
||||
strncpy (ftp_last_respline, line, sizeof (ftp_last_respline));
|
||||
ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
|
||||
*ret_line = line;
|
||||
return FTPOK;
|
||||
}
|
||||
@@ -960,23 +956,32 @@ ftp_retr (int csock, const char *file)
|
||||
/* Sends the LIST command to the server. If FILE is NULL, send just
|
||||
`LIST' (no space). */
|
||||
uerr_t
|
||||
ftp_list (int csock, const char *file, enum stype rs)
|
||||
ftp_list (int csock, const char *file, bool avoid_list_a, bool avoid_list,
|
||||
bool *list_a_used)
|
||||
{
|
||||
char *request, *respline;
|
||||
int nwritten;
|
||||
uerr_t err;
|
||||
bool ok = false;
|
||||
size_t i = 0;
|
||||
/* Try `LIST -a' first and revert to `LIST' in case of failure. */
|
||||
|
||||
*list_a_used = false;
|
||||
|
||||
/* 2013-10-12 Andrea Urbani (matfanjol)
|
||||
For more information about LIST and "LIST -a" please look at ftp.c,
|
||||
function getftp, text "__LIST_A_EXPLANATION__".
|
||||
|
||||
If somebody changes the following commands, please, checks also the
|
||||
later "i" variable. */
|
||||
const char *list_commands[] = { "LIST -a",
|
||||
"LIST" };
|
||||
|
||||
/* 2008-01-29 SMS. For a VMS FTP server, where "LIST -a" may not
|
||||
fail, but will never do what is desired here, skip directly to the
|
||||
simple "LIST" command (assumed to be the last one in the list).
|
||||
*/
|
||||
if (rs == ST_VMS)
|
||||
i = countof (list_commands)- 1;
|
||||
if (avoid_list_a)
|
||||
{
|
||||
i = countof (list_commands)- 1;
|
||||
DEBUGP (("(skipping \"LIST -a\")"));
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
/* Send request. */
|
||||
@@ -1000,6 +1005,8 @@ ftp_list (int csock, const char *file, enum stype rs)
|
||||
{
|
||||
err = FTPOK;
|
||||
ok = true;
|
||||
/* Which list command was used? */
|
||||
*list_a_used = (i == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1008,6 +1015,12 @@ ftp_list (int csock, const char *file, enum stype rs)
|
||||
xfree (respline);
|
||||
}
|
||||
++i;
|
||||
if ((avoid_list) && (i == 1))
|
||||
{
|
||||
/* I skip LIST */
|
||||
++i;
|
||||
DEBUGP (("(skipping \"LIST\")"));
|
||||
}
|
||||
} while (i < countof (list_commands) && !ok);
|
||||
|
||||
return err;
|
||||
@@ -1015,11 +1028,12 @@ ftp_list (int csock, const char *file, enum stype rs)
|
||||
|
||||
/* Sends the SYST command to the server. */
|
||||
uerr_t
|
||||
ftp_syst (int csock, enum stype *server_type)
|
||||
ftp_syst (int csock, enum stype *server_type, enum ustype *unix_type)
|
||||
{
|
||||
char *request, *respline;
|
||||
int nwritten;
|
||||
uerr_t err;
|
||||
char *ftp_last_respline;
|
||||
|
||||
/* Send SYST request. */
|
||||
request = ftp_request ("SYST", NULL);
|
||||
@@ -1041,6 +1055,8 @@ ftp_syst (int csock, enum stype *server_type)
|
||||
return FTPSRVERR;
|
||||
}
|
||||
|
||||
ftp_last_respline = strdup (respline);
|
||||
|
||||
/* Skip the number (215, but 200 (!!!) in case of VMS) */
|
||||
strtok (respline, " ");
|
||||
|
||||
@@ -1048,12 +1064,23 @@ ftp_syst (int csock, enum stype *server_type)
|
||||
first word of the server response)? */
|
||||
request = strtok (NULL, " ");
|
||||
|
||||
*unix_type = UST_OTHER;
|
||||
|
||||
if (request == NULL)
|
||||
*server_type = ST_OTHER;
|
||||
else if (!strcasecmp (request, "VMS"))
|
||||
*server_type = ST_VMS;
|
||||
else if (!strcasecmp (request, "UNIX"))
|
||||
*server_type = ST_UNIX;
|
||||
{
|
||||
*server_type = ST_UNIX;
|
||||
/* 2013-10-17 Andrea Urbani (matfanjol)
|
||||
I check more in depth the system type */
|
||||
if (!strncasecmp (ftp_last_respline, "215 UNIX Type: L8", 17))
|
||||
*unix_type = UST_TYPE_L8;
|
||||
else if (!strncasecmp (ftp_last_respline,
|
||||
"215 UNIX MultiNet Unix Emulation V5.3(93)", 41))
|
||||
*unix_type = UST_MULTINET;
|
||||
}
|
||||
else if (!strcasecmp (request, "WINDOWS_NT")
|
||||
|| !strcasecmp (request, "WINDOWS2000"))
|
||||
*server_type = ST_WINNT;
|
||||
@@ -1064,6 +1091,7 @@ ftp_syst (int csock, enum stype *server_type)
|
||||
else
|
||||
*server_type = ST_OTHER;
|
||||
|
||||
xfree (ftp_last_respline);
|
||||
xfree (respline);
|
||||
/* All OK. */
|
||||
return FTPOK;
|
||||
|
||||
188
src/ftp-ls.c
188
src/ftp-ls.c
@@ -68,16 +68,17 @@ symperms (const char *s)
|
||||
replaces all <TAB> character with <SPACE>. Returns the length of the
|
||||
modified line. */
|
||||
static int
|
||||
clean_line(char *line)
|
||||
clean_line (char *line, int len)
|
||||
{
|
||||
int len = strlen (line);
|
||||
if (!len) return 0;
|
||||
if (line[len - 1] == '\n')
|
||||
if (len <= 0) return 0;
|
||||
|
||||
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
|
||||
line[--len] = '\0';
|
||||
|
||||
if (!len) return 0;
|
||||
if (line[len - 1] == '\r')
|
||||
line[--len] = '\0';
|
||||
|
||||
for ( ; *line ; line++ ) if (*line == '\t') *line = ' ';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -102,9 +103,10 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
int hour, min, sec, ptype;
|
||||
struct tm timestruct, *tnow;
|
||||
time_t timenow;
|
||||
size_t bufsize = 0;
|
||||
|
||||
char *line, *tok, *ptok; /* tokenizer */
|
||||
struct fileinfo *dir, *l, cur; /* list creation */
|
||||
char *line = NULL, *tok, *ptok; /* tokenizer */
|
||||
struct fileinfo *dir, *l, cur; /* list creation */
|
||||
|
||||
fp = fopen (file, "rb");
|
||||
if (!fp)
|
||||
@@ -115,22 +117,16 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
dir = l = NULL;
|
||||
|
||||
/* Line loop to end of file: */
|
||||
while ((line = read_whole_line (fp)) != NULL)
|
||||
while ((len = getline (&line, &bufsize, fp)) > 0)
|
||||
{
|
||||
len = clean_line (line);
|
||||
len = clean_line (line, len);
|
||||
/* Skip if total... */
|
||||
if (!strncasecmp (line, "total", 5))
|
||||
{
|
||||
xfree (line);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
/* Get the first token (permissions). */
|
||||
tok = strtok (line, " ");
|
||||
if (!tok)
|
||||
{
|
||||
xfree (line);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
cur.name = NULL;
|
||||
cur.linkto = NULL;
|
||||
@@ -203,7 +199,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
if (next < 0) /* a month name was not encountered */
|
||||
{
|
||||
for (i = 0; i < 12; i++)
|
||||
if (!strcmp (tok, months[i]))
|
||||
if (!strcasecmp (tok, months[i]))
|
||||
break;
|
||||
/* If we got a month, it means the token before it is the
|
||||
size, and the filename is three tokens away. */
|
||||
@@ -368,7 +364,6 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
DEBUGP (("Skipping.\n"));
|
||||
xfree_null (cur.name);
|
||||
xfree_null (cur.linkto);
|
||||
xfree (line);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -416,10 +411,9 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
timestruct.tm_isdst = -1;
|
||||
l->tstamp = mktime (×truct); /* store the time-stamp */
|
||||
l->ptype = ptype;
|
||||
|
||||
xfree (line);
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
return dir;
|
||||
}
|
||||
@@ -431,9 +425,11 @@ ftp_parse_winnt_ls (const char *file)
|
||||
int len;
|
||||
int year, month, day; /* for time analysis */
|
||||
int hour, min;
|
||||
size_t bufsize = 0;
|
||||
struct tm timestruct;
|
||||
|
||||
char *line, *tok; /* tokenizer */
|
||||
char *line = NULL, *tok; /* tokenizer */
|
||||
char *filename;
|
||||
struct fileinfo *dir, *l, cur; /* list creation */
|
||||
|
||||
fp = fopen (file, "rb");
|
||||
@@ -445,43 +441,53 @@ ftp_parse_winnt_ls (const char *file)
|
||||
dir = l = NULL;
|
||||
|
||||
/* Line loop to end of file: */
|
||||
while ((line = read_whole_line (fp)) != NULL)
|
||||
while ((len = getline (&line, &bufsize, fp)) > 0)
|
||||
{
|
||||
len = clean_line (line);
|
||||
len = clean_line (line, len);
|
||||
|
||||
/* Extracting name is a bit of black magic and we have to do it
|
||||
before `strtok' inserted extra \0 characters in the line
|
||||
string. For the moment let us just suppose that the name starts at
|
||||
column 39 of the listing. This way we could also recognize
|
||||
filenames that begin with a series of space characters (but who
|
||||
really wants to use such filenames anyway?). */
|
||||
if (len < 40) goto continue_loop;
|
||||
tok = line + 39;
|
||||
cur.name = xstrdup(tok);
|
||||
DEBUGP (("Name: '%s'\n", cur.name));
|
||||
/* Name begins at 39 column of the listing if date presented in `mm-dd-yy'
|
||||
format or at 41 column if date presented in `mm-dd-yyyy' format. Thus,
|
||||
we cannot extract name before we parse date. Using this information we
|
||||
also can recognize filenames that begin with a series of space
|
||||
characters (but who really wants to use such filenames anyway?). */
|
||||
if (len < 40) continue;
|
||||
filename = line + 39;
|
||||
|
||||
/* First column: mm-dd-yy. Should atoi() on the month fail, january
|
||||
will be assumed. */
|
||||
/* First column: mm-dd-yy or mm-dd-yyyy. Should atoi() on the month fail,
|
||||
january will be assumed. */
|
||||
tok = strtok(line, "-");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
month = atoi(tok) - 1;
|
||||
if (month < 0) month = 0;
|
||||
tok = strtok(NULL, "-");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
day = atoi(tok);
|
||||
tok = strtok(NULL, " ");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
year = atoi(tok);
|
||||
/* Assuming the epoch starting at 1.1.1970 */
|
||||
if (year <= 70) year += 100;
|
||||
if (year <= 70)
|
||||
{
|
||||
year += 100;
|
||||
}
|
||||
else if (year >= 1900)
|
||||
{
|
||||
year -= 1900;
|
||||
filename += 2;
|
||||
}
|
||||
/* Now it is possible to determine the position of the first symbol in
|
||||
filename. */
|
||||
cur.name = xstrdup(filename);
|
||||
DEBUGP (("Name: '%s'\n", cur.name));
|
||||
|
||||
|
||||
/* Second column: hh:mm[AP]M, listing does not contain value for
|
||||
seconds */
|
||||
tok = strtok(NULL, ":");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
hour = atoi(tok);
|
||||
tok = strtok(NULL, "M");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
min = atoi(tok);
|
||||
/* Adjust hour from AM/PM. Just for the record, the sequence goes
|
||||
11:00AM, 12:00PM, 01:00PM ... 11:00PM, 12:00AM, 01:00AM . */
|
||||
@@ -512,9 +518,9 @@ ftp_parse_winnt_ls (const char *file)
|
||||
directories as the listing does not give us a clue) and filetype
|
||||
here. */
|
||||
tok = strtok(NULL, " ");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
while ((tok != NULL) && (*tok == '\0')) tok = strtok(NULL, " ");
|
||||
if (tok == NULL) goto continue_loop;
|
||||
if (tok == NULL) continue;
|
||||
if (*tok == '<')
|
||||
{
|
||||
cur.type = FT_DIRECTORY;
|
||||
@@ -553,11 +559,9 @@ ftp_parse_winnt_ls (const char *file)
|
||||
memcpy (l, &cur, sizeof (cur));
|
||||
l->next = NULL;
|
||||
}
|
||||
|
||||
continue_loop:
|
||||
xfree (line);
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
fclose(fp);
|
||||
return dir;
|
||||
}
|
||||
@@ -678,11 +682,12 @@ ftp_parse_vms_ls (const char *file)
|
||||
FILE *fp;
|
||||
int dt, i, j, len;
|
||||
int perms;
|
||||
size_t bufsize = 0;
|
||||
time_t timenow;
|
||||
struct tm *timestruct;
|
||||
char date_str[ 32];
|
||||
|
||||
char *line, *tok; /* tokenizer */
|
||||
char *line = NULL, *tok; /* tokenizer */
|
||||
struct fileinfo *dir, *l, cur; /* list creation */
|
||||
|
||||
fp = fopen (file, "r");
|
||||
@@ -695,52 +700,34 @@ ftp_parse_vms_ls (const char *file)
|
||||
|
||||
/* Skip blank lines, Directory heading, and more blank lines. */
|
||||
|
||||
j = 0; /* Expecting initial blank line(s). */
|
||||
while (1)
|
||||
for (j = 0; (i = getline (&line, &bufsize, fp)) > 0; )
|
||||
{
|
||||
line = read_whole_line (fp);
|
||||
if (line == NULL)
|
||||
i = clean_line (line, i);
|
||||
if (i <= 0)
|
||||
continue; /* Ignore blank line. */
|
||||
|
||||
if ((j == 0) && (line[i - 1] == ']'))
|
||||
{
|
||||
break;
|
||||
/* Found Directory heading line. Next non-blank line
|
||||
is significant. */
|
||||
j = 1;
|
||||
}
|
||||
else if (!strncmp (line, "Total of ", 9))
|
||||
{
|
||||
/* Found "Total of ..." footing line. No valid data
|
||||
will follow (empty directory). */
|
||||
i = 0; /* Arrange for early exit. */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = clean_line (line);
|
||||
if (i <= 0)
|
||||
{
|
||||
xfree (line); /* Free useless line storage. */
|
||||
continue; /* Blank line. Keep looking. */
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((j == 0) && (line[ i- 1] == ']'))
|
||||
{
|
||||
/* Found Directory heading line. Next non-blank line
|
||||
is significant.
|
||||
*/
|
||||
j = 1;
|
||||
}
|
||||
else if (!strncmp (line, "Total of ", 9))
|
||||
{
|
||||
/* Found "Total of ..." footing line. No valid data
|
||||
will follow (empty directory).
|
||||
*/
|
||||
xfree (line); /* Free useless line storage. */
|
||||
line = NULL; /* Arrange for early exit. */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; /* Must be significant data. */
|
||||
}
|
||||
}
|
||||
xfree (line); /* Free useless line storage. */
|
||||
break; /* Must be significant data. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Read remainder of file until the next blank line or EOF. */
|
||||
|
||||
while (line != NULL)
|
||||
while (i > 0)
|
||||
{
|
||||
char *p;
|
||||
|
||||
@@ -831,9 +818,8 @@ ftp_parse_vms_ls (const char *file)
|
||||
if (tok == NULL)
|
||||
{
|
||||
DEBUGP (("Getting additional line.\n"));
|
||||
xfree (line);
|
||||
line = read_whole_line (fp);
|
||||
if (!line)
|
||||
i = getline (&line, &bufsize, fp);
|
||||
if (i <= 0)
|
||||
{
|
||||
DEBUGP (("EOF. Leaving listing parser.\n"));
|
||||
break;
|
||||
@@ -842,14 +828,14 @@ ftp_parse_vms_ls (const char *file)
|
||||
/* Second line must begin with " ". Otherwise, it's a first
|
||||
line (and we may be confused).
|
||||
*/
|
||||
i = clean_line (line, i);
|
||||
if (i <= 0)
|
||||
{
|
||||
/* Blank line. End of significant file listing. */
|
||||
DEBUGP (("Blank line. Leaving listing parser.\n"));
|
||||
xfree (line); /* Free useless line storage. */
|
||||
break;
|
||||
}
|
||||
else if (line[ 0] != ' ')
|
||||
else if (line[0] != ' ')
|
||||
{
|
||||
DEBUGP (("Non-blank in column 1. Must be a new file name?\n"));
|
||||
continue;
|
||||
@@ -861,7 +847,6 @@ ftp_parse_vms_ls (const char *file)
|
||||
{
|
||||
/* Unexpected non-empty but apparently blank line. */
|
||||
DEBUGP (("Null token. Leaving listing parser.\n"));
|
||||
xfree (line); /* Free useless line storage. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -900,7 +885,7 @@ ftp_parse_vms_ls (const char *file)
|
||||
(sizeof( date_str)- strlen (date_str) - 1));
|
||||
DEBUGP (("Date time: >%s<\n", date_str));
|
||||
}
|
||||
else if (strchr ( tok, '[') != NULL)
|
||||
else if (strchr (tok, '[') != NULL)
|
||||
{
|
||||
/* Owner. (Ignore.) */
|
||||
DEBUGP (("Owner.\n"));
|
||||
@@ -910,7 +895,8 @@ ftp_parse_vms_ls (const char *file)
|
||||
/* Protections (permissions). */
|
||||
perms = 0;
|
||||
j = 0;
|
||||
for (i = 0; i < strlen( tok); i++)
|
||||
/*FIXME: Should not be using the variable like this. */
|
||||
for (i = 0; i < (int) strlen(tok); i++)
|
||||
{
|
||||
switch (tok[ i])
|
||||
{
|
||||
@@ -1004,21 +990,19 @@ ftp_parse_vms_ls (const char *file)
|
||||
l->next = NULL;
|
||||
}
|
||||
|
||||
/* Free old line storage. Read a new line. */
|
||||
xfree (line);
|
||||
line = read_whole_line (fp);
|
||||
if (line != NULL)
|
||||
i = getline (&line, &bufsize, fp);
|
||||
if (i > 0)
|
||||
{
|
||||
i = clean_line (line);
|
||||
i = clean_line (line, i);
|
||||
if (i <= 0)
|
||||
{
|
||||
{
|
||||
/* Blank line. End of significant file listing. */
|
||||
xfree (line); /* Free useless line storage. */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
return dir;
|
||||
}
|
||||
|
||||
413
src/ftp.c
413
src/ftp.c
@@ -1,6 +1,6 @@
|
||||
/* File Transfer Protocol support.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -70,6 +70,7 @@ typedef struct
|
||||
int csock; /* control connection socket */
|
||||
double dltime; /* time of the download in msecs */
|
||||
enum stype rs; /* remote system reported by ftp server */
|
||||
enum ustype rsu; /* when rs is ST_UNIX, here there are more details */
|
||||
char *id; /* initial directory */
|
||||
char *target; /* target file name */
|
||||
struct url *proxy; /* FTWK-style proxy */
|
||||
@@ -220,13 +221,13 @@ print_length (wgint size, wgint start, bool authoritative)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Length: %s"), number_to_static_string (size));
|
||||
if (size >= 1024)
|
||||
logprintf (LOG_VERBOSE, " (%s)", human_readable (size));
|
||||
logprintf (LOG_VERBOSE, " (%s)", human_readable (size, 10, 1));
|
||||
if (start > 0)
|
||||
{
|
||||
if (size - start >= 1024)
|
||||
logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),
|
||||
number_to_static_string (size - start),
|
||||
human_readable (size - start));
|
||||
human_readable (size - start, 10, 1));
|
||||
else
|
||||
logprintf (LOG_VERBOSE, _(", %s remaining"),
|
||||
number_to_static_string (size - start));
|
||||
@@ -242,7 +243,8 @@ static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **);
|
||||
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,
|
||||
wgint restval, ccon *con, int count, FILE *warc_tmp)
|
||||
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 */
|
||||
@@ -255,8 +257,10 @@ getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread,
|
||||
bool got_expected_bytes = false;
|
||||
bool rest_failed = false;
|
||||
int flags;
|
||||
wgint rd_size;
|
||||
wgint rd_size, previous_rd_size = 0;
|
||||
char type_char;
|
||||
bool try_again;
|
||||
bool list_a_used = false;
|
||||
|
||||
assert (con != NULL);
|
||||
assert (con->target != NULL);
|
||||
@@ -365,7 +369,7 @@ Error in server response, closing control connection.\n"));
|
||||
/* Third: Get the system type */
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, "==> SYST ... ");
|
||||
err = ftp_syst (csock, &con->rs);
|
||||
err = ftp_syst (csock, &con->rs, &con->rsu);
|
||||
/* FTPRERR */
|
||||
switch (err)
|
||||
{
|
||||
@@ -390,6 +394,44 @@ Error in server response, closing control connection.\n"));
|
||||
if (!opt.server_response && err != FTPSRVERR)
|
||||
logputs (LOG_VERBOSE, _("done. "));
|
||||
|
||||
/* 2013-10-17 Andrea Urbani (matfanjol)
|
||||
According to the system type I choose which
|
||||
list command will be used.
|
||||
If I don't know that system, I will try, the
|
||||
first time of each session, "LIST -a" and
|
||||
"LIST". (see __LIST_A_EXPLANATION__ below) */
|
||||
switch (con->rs)
|
||||
{
|
||||
case ST_VMS:
|
||||
/* About ST_VMS there is an old note:
|
||||
2008-01-29 SMS. For a VMS FTP server, where "LIST -a" may not
|
||||
fail, but will never do what is desired here,
|
||||
skip directly to the simple "LIST" command
|
||||
(assumed to be the last one in the list). */
|
||||
DEBUGP (("\nVMS: I know it and I will use \"LIST\" as standard list command\n"));
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST_A;
|
||||
break;
|
||||
case ST_UNIX:
|
||||
if (con->rsu == UST_MULTINET)
|
||||
{
|
||||
DEBUGP (("\nUNIX MultiNet: I know it and I will use \"LIST\" "
|
||||
"as standard list command\n"));
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST_A;
|
||||
}
|
||||
else if (con->rsu == UST_TYPE_L8)
|
||||
{
|
||||
DEBUGP (("\nUNIX TYPE L8: I know it and I will use \"LIST -a\" "
|
||||
"as standard list command\n"));
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fourth: Find the initial ftp directory */
|
||||
|
||||
if (!opt.server_response)
|
||||
@@ -616,16 +658,16 @@ Error in server response, closing control connection.\n"));
|
||||
The VMS restriction may be relaxed when the squirrely code
|
||||
above is reformed.
|
||||
*/
|
||||
if ((con->rs == ST_VMS) && (target[0] != '/'))
|
||||
{
|
||||
cwd_start = 0;
|
||||
DEBUGP (("Using two-step CWD for relative path.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((con->rs == ST_VMS) && (target[0] != '/'))
|
||||
{
|
||||
cwd_start = 0;
|
||||
DEBUGP (("Using two-step CWD for relative path.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Go straight to the target. */
|
||||
cwd_start = 1;
|
||||
}
|
||||
cwd_start = 1;
|
||||
}
|
||||
|
||||
/* At least one VMS FTP server (TCPware V5.6-2) can switch to
|
||||
a UNIX emulation mode when given a UNIX-like directory
|
||||
@@ -643,10 +685,10 @@ 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"));
|
||||
DEBUGP (("Using extra \"CWD []\" step for VMS server.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -656,22 +698,22 @@ Error in server response, closing control connection.\n"));
|
||||
/* 2004-09-20 SMS. */
|
||||
/* Sorry about the deviant indenting. Laziness. */
|
||||
|
||||
for (cwd_count = cwd_start; cwd_count < cwd_end; cwd_count++)
|
||||
{
|
||||
for (cwd_count = cwd_start; cwd_count < cwd_end; cwd_count++)
|
||||
{
|
||||
switch (cwd_count)
|
||||
{
|
||||
case 0:
|
||||
/* Step one (optional): Go to the initial directory,
|
||||
exactly as reported by the server.
|
||||
*/
|
||||
targ = con->id;
|
||||
/* Step one (optional): Go to the initial directory,
|
||||
exactly as reported by the server.
|
||||
*/
|
||||
targ = con->id;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* Step two: Go to the target directory. (Absolute or
|
||||
relative will work now.)
|
||||
*/
|
||||
targ = target;
|
||||
/* Step two: Go to the target directory. (Absolute or
|
||||
relative will work now.)
|
||||
*/
|
||||
targ = target;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -684,7 +726,7 @@ Error in server response, closing control connection.\n"));
|
||||
default:
|
||||
/* Can't happen. */
|
||||
assert (1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ", cwd_count,
|
||||
@@ -761,8 +803,12 @@ Error in server response, closing control connection.\n"));
|
||||
abort ();
|
||||
}
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, expected_bytes ? "%s\n" : _("done.\n"),
|
||||
number_to_static_string (expected_bytes));
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "%s\n",
|
||||
expected_bytes ?
|
||||
number_to_static_string (expected_bytes) :
|
||||
_("done.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd & DO_RETR && restval > 0 && restval == expected_bytes)
|
||||
@@ -775,6 +821,9 @@ Error in server response, closing control connection.\n"));
|
||||
return RETRFINISHED;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
try_again = false;
|
||||
/* If anything is to be retrieved, PORT (or PASV) must be sent. */
|
||||
if (cmd & (DO_LIST | DO_RETR))
|
||||
{
|
||||
@@ -938,42 +987,41 @@ Error in server response, closing control connection.\n"));
|
||||
if (cmd & DO_RETR)
|
||||
{
|
||||
/* If we're in spider mode, don't really retrieve anything except
|
||||
the directory listing and verify whether the given "file" exists. */
|
||||
the directory listing and verify whether the given "file" exists. */
|
||||
if (opt.spider)
|
||||
{
|
||||
bool exists = false;
|
||||
uerr_t res;
|
||||
struct fileinfo *f;
|
||||
res = ftp_get_listing (u, 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
|
||||
(e.g., when recursing). */
|
||||
con->cmd |= DO_RETR;
|
||||
if (res == RETROK)
|
||||
{
|
||||
while (f)
|
||||
{
|
||||
if (!strcmp (f->name, u->file))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
f = f->next;
|
||||
}
|
||||
bool exists = false;
|
||||
struct fileinfo *f;
|
||||
uerr_t _res = ftp_get_listing (u, 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
|
||||
(e.g., when recursing). */
|
||||
con->cmd |= DO_RETR;
|
||||
if (_res == RETROK)
|
||||
{
|
||||
while (f)
|
||||
{
|
||||
if (!strcmp (f->name, u->file))
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
f = f->next;
|
||||
}
|
||||
if (exists)
|
||||
{
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logprintf (LOG_NOTQUIET, _("File %s exists.\n"),
|
||||
quote (u->file));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logprintf (LOG_NOTQUIET, _("No such file %s.\n"),
|
||||
quote (u->file));
|
||||
}
|
||||
}
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logprintf (LOG_NOTQUIET, _("No such file %s.\n"),
|
||||
quote (u->file));
|
||||
}
|
||||
}
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
fd_close (dtsock);
|
||||
@@ -1031,7 +1079,7 @@ Error in server response, closing control connection.\n"));
|
||||
logputs (LOG_VERBOSE, _("done.\n"));
|
||||
|
||||
if (! got_expected_bytes)
|
||||
expected_bytes = ftp_expected_bytes (ftp_last_respline);
|
||||
expected_bytes = *last_expected_bytes;
|
||||
} /* do retrieve */
|
||||
|
||||
if (cmd & DO_LIST)
|
||||
@@ -1041,7 +1089,8 @@ Error in server response, closing control connection.\n"));
|
||||
/* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
|
||||
without arguments is better than `LIST .'; confirmed by
|
||||
RFC959. */
|
||||
err = ftp_list (csock, NULL, con->rs);
|
||||
err = ftp_list (csock, NULL, con->st&AVOID_LIST_A, con->st&AVOID_LIST, &list_a_used);
|
||||
|
||||
/* FTPRERR, WRITEFAILED */
|
||||
switch (err)
|
||||
{
|
||||
@@ -1079,7 +1128,7 @@ Error in server response, closing control connection.\n"));
|
||||
logputs (LOG_VERBOSE, _("done.\n"));
|
||||
|
||||
if (! got_expected_bytes)
|
||||
expected_bytes = ftp_expected_bytes (ftp_last_respline);
|
||||
expected_bytes = *last_expected_bytes;
|
||||
} /* cmd & DO_LIST */
|
||||
|
||||
if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
|
||||
@@ -1111,7 +1160,7 @@ Error in server response, closing control connection.\n"));
|
||||
/* Open the file -- if output_stream is set, use it instead. */
|
||||
|
||||
/* 2005-04-17 SMS.
|
||||
Note that having the output_stream ("-O") file opened in main()
|
||||
Note that having the output_stream ("-O") file opened in main
|
||||
(main.c) rather limits the ability in VMS to open the file
|
||||
differently for ASCII versus binary FTP here. (Of course, doing it
|
||||
there allows a open failure to be detected immediately, without first
|
||||
@@ -1184,20 +1233,19 @@ Error in server response, closing control connection.\n"));
|
||||
else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
|
||||
|| opt.output_document || count > 0)
|
||||
{
|
||||
if (opt.unlink && file_exists_p (con->target))
|
||||
{
|
||||
int res = unlink (con->target);
|
||||
if (res < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
|
||||
strerror (errno));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
fd_close (dtsock);
|
||||
fd_close (local_sock);
|
||||
return UNLINKERR;
|
||||
}
|
||||
}
|
||||
if (opt.unlink && file_exists_p (con->target))
|
||||
{
|
||||
if (unlink (con->target) < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
|
||||
strerror (errno));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
fd_close (dtsock);
|
||||
fd_close (local_sock);
|
||||
return UNLINKERR;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __VMS
|
||||
int open_id;
|
||||
@@ -1258,10 +1306,15 @@ Error in server response, closing control connection.\n"));
|
||||
|
||||
/* Get the contents of the document. */
|
||||
flags = 0;
|
||||
#ifdef ENABLE_METALINK
|
||||
if (opt.metalink_file && expected_bytes)
|
||||
/* If content-length is present, read that much; otherwise, read until EOF. */
|
||||
flags |= rb_read_exactly;
|
||||
#endif
|
||||
if (restval && rest_failed)
|
||||
flags |= rb_skip_startpos;
|
||||
rd_size = 0;
|
||||
res = fd_read_body (dtsock, fp,
|
||||
res = fd_read_body (con->target, dtsock, fp,
|
||||
expected_bytes ? expected_bytes - restval : 0,
|
||||
restval, &rd_size, qtyread, &con->dltime, flags, warc_tmp);
|
||||
|
||||
@@ -1298,6 +1351,7 @@ Error in server response, closing control connection.\n"));
|
||||
|
||||
/* Get the server to tell us if everything is retrieved. */
|
||||
err = ftp_response (csock, &respline);
|
||||
*last_expected_bytes = ftp_expected_bytes (respline);
|
||||
if (err != FTPOK)
|
||||
{
|
||||
/* The control connection is decidedly closed. Print the time
|
||||
@@ -1316,8 +1370,13 @@ Error in server response, closing control connection.\n"));
|
||||
/* If retrieval failed for any reason, return FTPRETRINT, but do not
|
||||
close socket, since the control connection is still alive. If
|
||||
there is something wrong with the control connection, it will
|
||||
become apparent later. */
|
||||
if (*respline != '2')
|
||||
become apparent later.
|
||||
In case of a metalink file download, proabably due to taking only a chunk
|
||||
of the file, respline becomes '2', even though file download is successful.
|
||||
TODO: Make sure exempting metalink downloads from this check does not cause
|
||||
any troubles.
|
||||
*/
|
||||
if (*respline != '2' && !opt.metalink_file)
|
||||
{
|
||||
xfree (respline);
|
||||
if (res != -1)
|
||||
@@ -1343,8 +1402,10 @@ Error in server response, closing control connection.\n"));
|
||||
}
|
||||
/* If it was a listing, and opt.server_response is true,
|
||||
print it out. */
|
||||
if (opt.server_response && (con->cmd & DO_LIST))
|
||||
if (con->cmd & DO_LIST)
|
||||
{
|
||||
if (opt.server_response)
|
||||
{
|
||||
/* 2005-02-25 SMS.
|
||||
Much of this work may already have been done, but repeating it should
|
||||
do no damage beyond wasting time.
|
||||
@@ -1367,22 +1428,115 @@ Error in server response, closing control connection.\n"));
|
||||
logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
|
||||
else
|
||||
{
|
||||
char *line;
|
||||
/* The lines are being read with read_whole_line because of
|
||||
char *line = NULL;
|
||||
size_t bufsize = 0;
|
||||
ssize_t len;
|
||||
|
||||
/* The lines are being read with getline because of
|
||||
no-buffering on opt.lfile. */
|
||||
while ((line = read_whole_line (fp)) != NULL)
|
||||
while ((len = getline (&line, &bufsize, fp)) > 0)
|
||||
{
|
||||
char *p = strchr (line, '\0');
|
||||
while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
|
||||
*--p = '\0';
|
||||
while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
|
||||
line[--len] = '\0';
|
||||
logprintf (LOG_ALWAYS, "%s\n",
|
||||
quotearg_style (escape_quoting_style, line));
|
||||
xfree (line);
|
||||
}
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
}
|
||||
} /* con->cmd & DO_LIST && server_response */
|
||||
} /* server_response */
|
||||
|
||||
/* 2013-10-17 Andrea Urbani (matfanjol)
|
||||
< __LIST_A_EXPLANATION__ >
|
||||
After the SYST command, looks if it knows that system.
|
||||
If yes, wget will force the use of "LIST" or "LIST -a".
|
||||
If no, wget will try, only the first time of each session, before the
|
||||
"LIST -a" command and after the "LIST".
|
||||
If "LIST -a" works and returns more or equal data of the "LIST",
|
||||
"LIST -a" will be the standard list command for all the session.
|
||||
If "LIST -a" fails or returns less data than "LIST" (think on the case
|
||||
of an existing file called "-a"), "LIST" will be the standard list
|
||||
command for all the session.
|
||||
("LIST -a" is used to get also the hidden files)
|
||||
|
||||
*/
|
||||
if (!(con->st & LIST_AFTER_LIST_A_CHECK_DONE))
|
||||
{
|
||||
/* We still have to check "LIST" after the first "LIST -a" to see
|
||||
if with "LIST" we get more data than "LIST -a", that means
|
||||
"LIST -a" returned files/folders with "-a" name. */
|
||||
if (con->st & AVOID_LIST_A)
|
||||
{
|
||||
/* LIST was used in this cycle.
|
||||
Let's see the result. */
|
||||
if (rd_size > previous_rd_size)
|
||||
{
|
||||
/* LIST returns more data than "LIST -a".
|
||||
"LIST" is the official command to use. */
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
DEBUGP (("LIST returned more data than \"LIST -a\": "
|
||||
"I will use \"LIST\" as standard list command\n"));
|
||||
}
|
||||
else if (previous_rd_size > rd_size)
|
||||
{
|
||||
/* "LIST -a" returned more data then LIST.
|
||||
"LIST -a" is the official command to use. */
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST;
|
||||
con->st &= ~AVOID_LIST_A;
|
||||
/* Sorry, please, download again the "LIST -a"... */
|
||||
try_again = true;
|
||||
DEBUGP (("LIST returned less data than \"LIST -a\": I will "
|
||||
"use \"LIST -a\" as standard list command\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* LIST and "LIST -a" return the same data. */
|
||||
if (rd_size == 0)
|
||||
{
|
||||
/* Same empty data. We will check both again because
|
||||
we cannot check if "LIST -a" has returned an empty
|
||||
folder instead of a folder content. */
|
||||
con->st &= ~AVOID_LIST_A;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Same data, so, better to take "LIST -a" that
|
||||
shows also hidden files/folders (when present) */
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST;
|
||||
con->st &= ~AVOID_LIST_A;
|
||||
DEBUGP (("LIST returned the same amount of data of "
|
||||
"\"LIST -a\": I will use \"LIST -a\" as standard "
|
||||
"list command\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* In this cycle "LIST -a" should being used. Is it true? */
|
||||
if (list_a_used)
|
||||
{
|
||||
/* Yes, it is.
|
||||
OK, let's save the amount of data and try again
|
||||
with LIST */
|
||||
previous_rd_size = rd_size;
|
||||
try_again = true;
|
||||
con->st |= AVOID_LIST_A;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No: something happens and LIST was used.
|
||||
This means "LIST -a" raises an error. */
|
||||
con->st |= LIST_AFTER_LIST_A_CHECK_DONE;
|
||||
con->st |= AVOID_LIST_A;
|
||||
DEBUGP (("\"LIST -a\" failed: I will use \"LIST\" "
|
||||
"as standard list command\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (try_again);
|
||||
return RETRFINISHED;
|
||||
}
|
||||
|
||||
@@ -1392,7 +1546,7 @@ Error in server response, closing control connection.\n"));
|
||||
This loop either gets commands from con, or (if ON_YOUR_OWN is
|
||||
set), makes them up to retrieve the file given by the URL. */
|
||||
static uerr_t
|
||||
ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file)
|
||||
ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file, struct range *range)
|
||||
{
|
||||
int count, orig_lp;
|
||||
wgint restval, len = 0, qtyread = 0;
|
||||
@@ -1405,6 +1559,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
bool warc_enabled = (opt.warc_filename != NULL);
|
||||
FILE *warc_tmp = NULL;
|
||||
ip_address *warc_ip = NULL;
|
||||
wgint last_expected_bytes = 0;
|
||||
|
||||
/* Get the target, and set the name for the message accordingly. */
|
||||
if ((f == NULL) && (con->target))
|
||||
@@ -1424,7 +1579,12 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
|
||||
/* If the output_document was given, then this check was already done and
|
||||
the file didn't exist. Hence the !opt.output_document */
|
||||
if (opt.noclobber && !opt.output_document && file_exists_p (con->target))
|
||||
|
||||
/* If we receive .listing file it is necessary to determine system type of the ftp
|
||||
server even if opn.noclobber is given. Thus we must ignore opt.noclobber in
|
||||
order to establish connection with the server and get system type. */
|
||||
if (opt.noclobber && !opt.output_document && file_exists_p (con->target)
|
||||
&& !((con->cmd & DO_LIST) && !(con->cmd & DO_RETR)))
|
||||
{
|
||||
logprintf (LOG_VERBOSE,
|
||||
_("File %s already there; not retrieving.\n"), quote (con->target));
|
||||
@@ -1442,21 +1602,6 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
|
||||
orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
|
||||
|
||||
/* For file RETR requests, we can write a WARC record.
|
||||
We record the file contents to a temporary file. */
|
||||
if (warc_enabled && (con->cmd & DO_RETR))
|
||||
{
|
||||
warc_tmp = warc_tempfile ();
|
||||
if (warc_tmp == NULL)
|
||||
return WARC_TMP_FOPENERR;
|
||||
|
||||
if (!con->proxy && con->csock != -1)
|
||||
{
|
||||
warc_ip = (ip_address *) alloca (sizeof (ip_address));
|
||||
socket_ip_address (con->csock, warc_ip, ENDPOINT_PEER);
|
||||
}
|
||||
}
|
||||
|
||||
/* THE loop. */
|
||||
do
|
||||
{
|
||||
@@ -1484,9 +1629,26 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
con->cmd |= DO_CWD;
|
||||
}
|
||||
|
||||
/* For file RETR requests, we can write a WARC record.
|
||||
We record the file contents to a temporary file. */
|
||||
if (warc_enabled && (con->cmd & DO_RETR) && warc_tmp == NULL)
|
||||
{
|
||||
warc_tmp = warc_tempfile ();
|
||||
if (warc_tmp == NULL)
|
||||
return WARC_TMP_FOPENERR;
|
||||
|
||||
if (!con->proxy && con->csock != -1)
|
||||
{
|
||||
warc_ip = (ip_address *) alloca (sizeof (ip_address));
|
||||
socket_ip_address (con->csock, warc_ip, ENDPOINT_PEER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide whether or not to restart. */
|
||||
if (con->cmd & DO_LIST)
|
||||
restval = 0;
|
||||
else if (opt.start_pos >= 0)
|
||||
restval = opt.start_pos;
|
||||
else if (opt.always_rest
|
||||
&& stat (locf, &st) == 0
|
||||
&& S_ISREG (st.st_mode))
|
||||
@@ -1499,6 +1661,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
else
|
||||
restval = 0;
|
||||
|
||||
|
||||
/* Get the current time string. */
|
||||
tms = datetime_str (time (NULL));
|
||||
/* Print fetch message, if opt.verbose. */
|
||||
@@ -1522,9 +1685,23 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
else
|
||||
len = 0;
|
||||
|
||||
/* If range is not NULL, then this is a segmented download. Get the relevant
|
||||
segment information from the specified range parameter. */
|
||||
if (range)
|
||||
{
|
||||
restval = range->first_byte;
|
||||
/* It is not the length in the usual sense, but this is the correct
|
||||
value for getftp to use. */
|
||||
len = range->last_byte + 1;
|
||||
}
|
||||
|
||||
/* 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, warc_tmp);
|
||||
err = getftp (u, len, &qtyread, restval, con, count, &last_expected_bytes,
|
||||
warc_tmp);
|
||||
|
||||
if (range)
|
||||
range->bytes_covered = qtyread;
|
||||
|
||||
if (con->csock == -1)
|
||||
con->st &= ~DONE_CWD;
|
||||
@@ -1619,7 +1796,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
/* warc_write_resource_record has also closed warc_tmp. */
|
||||
}
|
||||
|
||||
if ((con->cmd & DO_LIST))
|
||||
if (con->cmd & DO_LIST)
|
||||
/* This is a directory listing file. */
|
||||
{
|
||||
if (!opt.remove_listing)
|
||||
@@ -1660,7 +1837,7 @@ Removing file due to --delete-after in ftp_loop_internal():\n"));
|
||||
else
|
||||
con->cmd &= ~LEAVE_PENDING;
|
||||
|
||||
if (local_file)
|
||||
if (local_file && !*local_file)
|
||||
*local_file = xstrdup (locf);
|
||||
|
||||
return RETROK;
|
||||
@@ -1698,7 +1875,7 @@ ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
|
||||
|
||||
con->target = xstrdup (lf);
|
||||
xfree (lf);
|
||||
err = ftp_loop_internal (u, NULL, con, NULL);
|
||||
err = ftp_loop_internal (u, NULL, con, NULL, NULL);
|
||||
lf = xstrdup (con->target);
|
||||
xfree (con->target);
|
||||
con->target = old_target;
|
||||
@@ -1893,7 +2070,7 @@ Already have correct symlink %s -> %s\n\n"),
|
||||
else /* opt.retr_symlinks */
|
||||
{
|
||||
if (dlthis)
|
||||
err = ftp_loop_internal (u, f, con, NULL);
|
||||
err = ftp_loop_internal (u, f, con, NULL, NULL);
|
||||
} /* opt.retr_symlinks */
|
||||
break;
|
||||
case FT_DIRECTORY:
|
||||
@@ -1904,7 +2081,7 @@ Already have correct symlink %s -> %s\n\n"),
|
||||
case FT_PLAINFILE:
|
||||
/* Call the retrieve loop. */
|
||||
if (dlthis)
|
||||
err = ftp_loop_internal (u, f, con, NULL);
|
||||
err = ftp_loop_internal (u, f, con, NULL, NULL);
|
||||
break;
|
||||
case FT_UNKNOWN:
|
||||
logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
|
||||
@@ -2187,7 +2364,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
|
||||
{
|
||||
/* Let's try retrieving it anyway. */
|
||||
con->st |= ON_YOUR_OWN;
|
||||
res = ftp_loop_internal (u, NULL, con, NULL);
|
||||
res = ftp_loop_internal (u, NULL, con, NULL, NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2208,7 +2385,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
|
||||
encoded into a URL. */
|
||||
uerr_t
|
||||
ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
|
||||
bool recursive, bool glob)
|
||||
bool recursive, bool glob, struct range *range)
|
||||
{
|
||||
ccon con; /* FTP connection */
|
||||
uerr_t res;
|
||||
@@ -2222,6 +2399,10 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
|
||||
con.rs = ST_UNIX;
|
||||
con.id = NULL;
|
||||
con.proxy = proxy;
|
||||
/* To let ftp_loop_internal AND getftp know of the desired file name. Added
|
||||
while implementing metalink support to wget. */
|
||||
if(local_file && *local_file)
|
||||
con.target = xstrdup (*local_file);
|
||||
|
||||
/* If the file name is empty, the user probably wants a directory
|
||||
index. We'll provide one, properly HTML-ized. Unless
|
||||
@@ -2278,16 +2459,16 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
|
||||
file_part = u->path;
|
||||
ispattern = has_wildcards_p (file_part);
|
||||
}
|
||||
if (ispattern || recursive || opt.timestamping)
|
||||
if (ispattern || recursive || opt.timestamping || opt.preserve_perm)
|
||||
{
|
||||
/* ftp_retrieve_glob is a catch-all function that gets called
|
||||
if we need globbing, time-stamping or recursion. Its
|
||||
third argument is just what we really need. */
|
||||
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,
|
||||
ispattern ? GLOB_GLOBALL : GLOB_GETONE);
|
||||
}
|
||||
else
|
||||
res = ftp_loop_internal (u, NULL, &con, local_file);
|
||||
res = ftp_loop_internal (u, NULL, &con, local_file, range);
|
||||
}
|
||||
if (res == FTPOK)
|
||||
res = RETROK;
|
||||
|
||||
69
src/ftp.h
69
src/ftp.h
@@ -32,6 +32,8 @@ as that of the covered work. */
|
||||
#ifndef FTP_H
|
||||
#define FTP_H
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include "host.h"
|
||||
|
||||
/* System types. */
|
||||
@@ -45,6 +47,14 @@ enum stype
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
/* Extensions of the ST_UNIX */
|
||||
enum ustype
|
||||
{
|
||||
UST_TYPE_L8,
|
||||
UST_MULTINET,
|
||||
UST_OTHER
|
||||
};
|
||||
|
||||
extern char ftp_last_respline[];
|
||||
|
||||
uerr_t ftp_response (int, char **);
|
||||
@@ -61,8 +71,8 @@ uerr_t ftp_type (int, int);
|
||||
uerr_t ftp_cwd (int, const char *);
|
||||
uerr_t ftp_retr (int, const char *);
|
||||
uerr_t ftp_rest (int, wgint);
|
||||
uerr_t ftp_list (int, const char *, enum stype);
|
||||
uerr_t ftp_syst (int, enum stype *);
|
||||
uerr_t ftp_list (int, const char *, bool, bool, bool *);
|
||||
uerr_t ftp_syst (int, enum stype *, enum ustype *);
|
||||
uerr_t ftp_pwd (int, char **);
|
||||
uerr_t ftp_size (int, const char *, wgint *);
|
||||
|
||||
@@ -98,38 +108,53 @@ enum parsetype
|
||||
/* Information about one filename in a linked list. */
|
||||
struct fileinfo
|
||||
{
|
||||
enum ftype type; /* file type */
|
||||
char *name; /* file name */
|
||||
wgint size; /* file size */
|
||||
long tstamp; /* time-stamp */
|
||||
enum parsetype ptype; /* time parsing */
|
||||
int perms; /* file permissions */
|
||||
char *linkto; /* link to which file points */
|
||||
struct fileinfo *prev; /* previous... */
|
||||
struct fileinfo *next; /* ...and next structure. */
|
||||
enum ftype type; /* file type */
|
||||
char *name; /* file name */
|
||||
wgint size; /* file size */
|
||||
long tstamp; /* time-stamp */
|
||||
enum parsetype ptype; /* time parsing */
|
||||
int perms; /* file permissions */
|
||||
char *linkto; /* link to which file points */
|
||||
struct fileinfo *prev; /* previous... */
|
||||
struct fileinfo *next; /* ...and next structure. */
|
||||
};
|
||||
|
||||
/* Commands for FTP functions. */
|
||||
enum wget_ftp_command
|
||||
{
|
||||
DO_LOGIN = 0x0001, /* Connect and login to the server. */
|
||||
DO_CWD = 0x0002, /* Change current directory. */
|
||||
DO_RETR = 0x0004, /* Retrieve the file. */
|
||||
DO_LIST = 0x0008, /* Retrieve the directory list. */
|
||||
LEAVE_PENDING = 0x0010 /* Do not close the socket. */
|
||||
DO_LOGIN = 0x0001, /* Connect and login to the server. */
|
||||
DO_CWD = 0x0002, /* Change current directory. */
|
||||
DO_RETR = 0x0004, /* Retrieve the file. */
|
||||
DO_LIST = 0x0008, /* Retrieve the directory list. */
|
||||
LEAVE_PENDING = 0x0010 /* Do not close the socket. */
|
||||
};
|
||||
|
||||
enum wget_ftp_fstatus
|
||||
{
|
||||
NOTHING = 0x0000, /* Nothing done yet. */
|
||||
ON_YOUR_OWN = 0x0001, /* The ftp_loop_internal sets the
|
||||
defaults. */
|
||||
DONE_CWD = 0x0002 /* The current working directory is
|
||||
correct. */
|
||||
NOTHING = 0x0000, /* Nothing done yet. */
|
||||
ON_YOUR_OWN = 0x0001, /* The ftp_loop_internal sets the
|
||||
defaults. */
|
||||
DONE_CWD = 0x0002, /* The current working directory is
|
||||
correct. */
|
||||
|
||||
/* 2013-10-17 Andrea Urbani (matfanjol)
|
||||
For more information about the following entries, please,
|
||||
look at ftp.c, function getftp, text "__LIST_A_EXPLANATION__". */
|
||||
AVOID_LIST_A = 0x0004, /* It tells us if during this
|
||||
session we have to avoid the use
|
||||
of "LIST -a".*/
|
||||
AVOID_LIST = 0x0008, /* It tells us if during this
|
||||
session we have to avoid to use
|
||||
"LIST". */
|
||||
LIST_AFTER_LIST_A_CHECK_DONE = 0x0010
|
||||
/* It tells us if we have already
|
||||
checked "LIST" after the first
|
||||
"LIST -a" to handle the case of
|
||||
file/folders named "-a". */
|
||||
};
|
||||
|
||||
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 *, char **, int *, struct url *, bool, bool, struct range *);
|
||||
|
||||
uerr_t ftp_index (const char *, struct url *, struct fileinfo *);
|
||||
|
||||
|
||||
@@ -133,8 +133,8 @@ inline
|
||||
#endif
|
||||
static const char *
|
||||
pgettext_aux (const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
int category)
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
const char *translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
if (translation == msg_ctxt_id)
|
||||
@@ -152,9 +152,9 @@ inline
|
||||
#endif
|
||||
static const char *
|
||||
npgettext_aux (const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
{
|
||||
const char *translation =
|
||||
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
|
||||
@@ -192,8 +192,8 @@ inline
|
||||
#endif
|
||||
static const char *
|
||||
dcpgettext_expr (const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
int category)
|
||||
const char *msgctxt, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
@@ -215,10 +215,10 @@ dcpgettext_expr (const char *domain,
|
||||
translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf)
|
||||
free (msg_ctxt_id);
|
||||
free (msg_ctxt_id);
|
||||
#endif
|
||||
if (translation != msg_ctxt_id)
|
||||
return translation;
|
||||
return translation;
|
||||
}
|
||||
return msgid;
|
||||
}
|
||||
@@ -237,9 +237,9 @@ inline
|
||||
#endif
|
||||
static const char *
|
||||
dcnpgettext_expr (const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
const char *msgctxt, const char *msgid,
|
||||
const char *msgid_plural, unsigned long int n,
|
||||
int category)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
@@ -261,10 +261,10 @@ dcnpgettext_expr (const char *domain,
|
||||
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf)
|
||||
free (msg_ctxt_id);
|
||||
free (msg_ctxt_id);
|
||||
#endif
|
||||
if (!(translation == msg_ctxt_id || translation == msgid_plural))
|
||||
return translation;
|
||||
return translation;
|
||||
}
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
}
|
||||
|
||||
244
src/gnutls.c
244
src/gnutls.c
@@ -30,7 +30,6 @@ as that of the covered work. */
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
@@ -46,6 +45,7 @@ as that of the covered work. */
|
||||
#include "connect.h"
|
||||
#include "url.h"
|
||||
#include "ptimer.h"
|
||||
#include "hash.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#include <sys/fcntl.h>
|
||||
@@ -81,49 +81,76 @@ ssl_init (void)
|
||||
{
|
||||
/* Becomes true if GnuTLS is initialized. */
|
||||
static bool ssl_initialized = false;
|
||||
const char *ca_directory;
|
||||
DIR *dir;
|
||||
int ncerts = -1;
|
||||
|
||||
/* GnuTLS should be initialized only once. */
|
||||
if (ssl_initialized)
|
||||
return true;
|
||||
|
||||
const char *ca_directory;
|
||||
DIR *dir;
|
||||
|
||||
gnutls_global_init ();
|
||||
gnutls_certificate_allocate_credentials (&credentials);
|
||||
gnutls_certificate_set_verify_flags(credentials,
|
||||
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
|
||||
gnutls_certificate_set_verify_flags (credentials,
|
||||
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
|
||||
|
||||
ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
|
||||
#if GNUTLS_VERSION_MAJOR >= 3
|
||||
if (!opt.ca_directory)
|
||||
ncerts = gnutls_certificate_set_x509_system_trust (credentials);
|
||||
#endif
|
||||
|
||||
dir = opendir (ca_directory);
|
||||
if (dir == NULL)
|
||||
/* If GnuTLS version is too old or CA loading failed, fallback to old behaviour.
|
||||
* Also use old behaviour if the CA directory is user-provided. */
|
||||
if (ncerts <= 0)
|
||||
{
|
||||
if (opt.ca_directory)
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
|
||||
opt.ca_directory);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct dirent *dent;
|
||||
while ((dent = readdir (dir)) != NULL)
|
||||
ca_directory = opt.ca_directory ? opt.ca_directory : "/etc/ssl/certs";
|
||||
if ((dir = opendir (ca_directory)) == NULL)
|
||||
{
|
||||
struct stat st;
|
||||
char *ca_file;
|
||||
asprintf (&ca_file, "%s/%s", ca_directory, dent->d_name);
|
||||
|
||||
stat (ca_file, &st);
|
||||
|
||||
if (S_ISREG (st.st_mode))
|
||||
gnutls_certificate_set_x509_trust_file (credentials, ca_file,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
|
||||
free (ca_file);
|
||||
if (opt.ca_directory && *opt.ca_directory)
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: Cannot open directory %s.\n"),
|
||||
opt.ca_directory);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct hash_table *inode_map = hash_table_new (196, NULL, NULL);
|
||||
struct dirent *dent;
|
||||
size_t dirlen = strlen(ca_directory);
|
||||
int rc;
|
||||
|
||||
closedir (dir);
|
||||
ncerts = 0;
|
||||
|
||||
while ((dent = readdir (dir)) != NULL)
|
||||
{
|
||||
struct stat st;
|
||||
char ca_file[dirlen + strlen(dent->d_name) + 2];
|
||||
|
||||
snprintf (ca_file, sizeof(ca_file), "%s/%s", ca_directory, dent->d_name);
|
||||
if (stat (ca_file, &st) != 0)
|
||||
continue;
|
||||
|
||||
if (! S_ISREG (st.st_mode))
|
||||
continue;
|
||||
|
||||
/* avoid loading the same file twice by checking the inode. */
|
||||
if (hash_table_contains (inode_map, (void *)(intptr_t) st.st_ino))
|
||||
continue;
|
||||
|
||||
hash_table_put (inode_map, (void *)(intptr_t) st.st_ino, NULL);
|
||||
if ((rc = gnutls_certificate_set_x509_trust_file (credentials, ca_file,
|
||||
GNUTLS_X509_FMT_PEM)) <= 0)
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: Failed to open cert %s: (%d).\n"),
|
||||
ca_file, rc);
|
||||
else
|
||||
ncerts += rc;
|
||||
}
|
||||
|
||||
hash_table_destroy (inode_map);
|
||||
closedir (dir);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGP (("Certificates loaded: %d\n", ncerts));
|
||||
|
||||
/* Use the private key from the cert file unless otherwise specified. */
|
||||
if (opt.cert_file && !opt.private_key)
|
||||
{
|
||||
@@ -141,17 +168,17 @@ ssl_init (void)
|
||||
{
|
||||
int type;
|
||||
if (opt.private_key_type != opt.cert_type)
|
||||
{
|
||||
/* GnuTLS can't handle this */
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
|
||||
{
|
||||
/* GnuTLS can't handle this */
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: GnuTLS requires the key and the \
|
||||
cert to be of the same type.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
type = key_type_to_gnutls_type (opt.private_key_type);
|
||||
|
||||
gnutls_certificate_set_x509_key_file (credentials, opt.cert_file,
|
||||
opt.private_key,
|
||||
type);
|
||||
opt.private_key,
|
||||
type);
|
||||
}
|
||||
|
||||
if (opt.ca_cert)
|
||||
@@ -278,7 +305,7 @@ wgnutls_read (int fd, char *buf, int bufsize, void *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
wgnutls_write (int fd, char *buf, int bufsize, void *arg)
|
||||
wgnutls_write (int fd _GL_UNUSED, char *buf, int bufsize, void *arg)
|
||||
{
|
||||
int ret;
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
@@ -315,7 +342,7 @@ wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (bufsize > sizeof ctx->peekbuf)
|
||||
if (bufsize > (int) sizeof ctx->peekbuf)
|
||||
bufsize = sizeof ctx->peekbuf;
|
||||
|
||||
if (bufsize > offset)
|
||||
@@ -346,7 +373,7 @@ wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
}
|
||||
|
||||
static const char *
|
||||
wgnutls_errstr (int fd, void *arg)
|
||||
wgnutls_errstr (int fd _GL_UNUSED, void *arg)
|
||||
{
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
return gnutls_strerror (ctx->last_error);
|
||||
@@ -374,16 +401,20 @@ static struct transport_implementation wgnutls_transport =
|
||||
bool
|
||||
ssl_connect_wget (int fd, const char *hostname)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
int flags = 0;
|
||||
#endif
|
||||
struct wgnutls_transport_context *ctx;
|
||||
gnutls_session_t session;
|
||||
int err;
|
||||
int err,alert;
|
||||
gnutls_init (&session, GNUTLS_CLIENT);
|
||||
const char *str;
|
||||
|
||||
/* 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));
|
||||
strlen (hostname));
|
||||
}
|
||||
|
||||
gnutls_set_default_priority (session);
|
||||
@@ -391,7 +422,11 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
#ifndef FD_TO_SOCKET
|
||||
# define FD_TO_SOCKET(X) (X)
|
||||
#endif
|
||||
#ifdef HAVE_INTPTR_T
|
||||
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) (intptr_t) FD_TO_SOCKET (fd));
|
||||
#else
|
||||
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) FD_TO_SOCKET (fd));
|
||||
#endif
|
||||
|
||||
err = 0;
|
||||
#if HAVE_GNUTLS_PRIORITY_SET_DIRECT
|
||||
@@ -401,11 +436,17 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
break;
|
||||
case secure_protocol_sslv2:
|
||||
case secure_protocol_sslv3:
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL", NULL);
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0", NULL);
|
||||
break;
|
||||
case secure_protocol_tlsv1:
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0", NULL);
|
||||
break;
|
||||
case secure_protocol_pfs:
|
||||
err = gnutls_priority_set_direct (session, "PFS", NULL);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
/* fallback if PFS is not available */
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-RSA", NULL);
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
@@ -440,10 +481,82 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
return false;
|
||||
}
|
||||
|
||||
err = gnutls_handshake (session);
|
||||
if (opt.connect_timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
flags = fcntl (fd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
|
||||
return -1;
|
||||
#else
|
||||
/* XXX: Assume it was blocking before. */
|
||||
const int one = 1;
|
||||
if (ioctl (fd, FIONBIO, &one) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We don't stop the handshake process for non-fatal errors */
|
||||
do
|
||||
{
|
||||
err = gnutls_handshake (session);
|
||||
|
||||
if (opt.connect_timeout && err == GNUTLS_E_AGAIN)
|
||||
{
|
||||
if (gnutls_record_get_direction (session))
|
||||
{
|
||||
/* wait for writeability */
|
||||
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait for readability */
|
||||
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_READ);
|
||||
}
|
||||
|
||||
if (err <= 0)
|
||||
{
|
||||
if (err == 0)
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
err = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
err = GNUTLS_E_AGAIN;
|
||||
}
|
||||
else if (err < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
|
||||
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
|
||||
err == GNUTLS_E_FATAL_ALERT_RECEIVED)
|
||||
{
|
||||
alert = gnutls_alert_get (session);
|
||||
str = gnutls_alert_get_name (alert);
|
||||
if (str == NULL)
|
||||
str = "(unknown)";
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n", alert, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (err && gnutls_error_is_fatal (err) == 0);
|
||||
|
||||
if (opt.connect_timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
return -1;
|
||||
#else
|
||||
const int zero = 0;
|
||||
if (ioctl (fd, FIONBIO, &zero) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
|
||||
gnutls_deinit (session);
|
||||
return false;
|
||||
}
|
||||
@@ -454,6 +567,14 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
return true;
|
||||
}
|
||||
|
||||
#define _CHECK_CERT(flag,msg) \
|
||||
if (status & (flag))\
|
||||
{\
|
||||
logprintf (LOG_NOTQUIET, (msg),\
|
||||
severity, quote (host));\
|
||||
success = false;\
|
||||
}
|
||||
|
||||
bool
|
||||
ssl_check_certificate (int fd, const char *host)
|
||||
{
|
||||
@@ -476,24 +597,13 @@ ssl_check_certificate (int fd, const char *host)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status & GNUTLS_CERT_INVALID)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("%s: The certificate of %s is not trusted.\n"),
|
||||
severity, quote (host));
|
||||
success = false;
|
||||
}
|
||||
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("%s: The certificate of %s hasn't got a known issuer.\n"),
|
||||
severity, quote (host));
|
||||
success = false;
|
||||
}
|
||||
if (status & GNUTLS_CERT_REVOKED)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("%s: The certificate of %s has been revoked.\n"),
|
||||
severity, quote (host));
|
||||
success = false;
|
||||
}
|
||||
_CHECK_CERT (GNUTLS_CERT_INVALID, _("%s: The certificate of %s is not trusted.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_SIGNER_NOT_FOUND, _("%s: The certificate of %s hasn't got a known issuer.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_REVOKED, _("%s: The certificate of %s has been revoked.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_SIGNER_NOT_CA, _("%s: The certificate signer of %s was not a CA.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_INSECURE_ALGORITHM, _("%s: The certificate of %s was signed using an insecure algorithm.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_NOT_ACTIVATED, _("%s: The certificate of %s is not yet activated.\n"));
|
||||
_CHECK_CERT (GNUTLS_CERT_EXPIRED, _("%s: The certificate of %s has expired.\n"));
|
||||
|
||||
if (gnutls_certificate_type_get (ctx->session) == GNUTLS_CRT_X509)
|
||||
{
|
||||
@@ -515,7 +625,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("No certificate found\n"));
|
||||
success = false;
|
||||
goto out;
|
||||
goto crt_deinit;
|
||||
}
|
||||
err = gnutls_x509_crt_import (cert, cert_list, GNUTLS_X509_FMT_DER);
|
||||
if (err < 0)
|
||||
@@ -523,7 +633,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
logprintf (LOG_NOTQUIET, _("Error parsing certificate: %s\n"),
|
||||
gnutls_strerror (err));
|
||||
success = false;
|
||||
goto out;
|
||||
goto crt_deinit;
|
||||
}
|
||||
if (now < gnutls_x509_crt_get_activation_time (cert))
|
||||
{
|
||||
@@ -542,8 +652,14 @@ ssl_check_certificate (int fd, const char *host)
|
||||
quote (host));
|
||||
success = false;
|
||||
}
|
||||
crt_deinit:
|
||||
gnutls_x509_crt_deinit (cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("Certificate must be X.509\n"));
|
||||
success = false;
|
||||
}
|
||||
|
||||
out:
|
||||
return opt.check_cert ? success : true;
|
||||
|
||||
15
src/hash.c
15
src/hash.c
@@ -55,11 +55,7 @@ as that of the covered work. */
|
||||
# endif
|
||||
# include <ctype.h>
|
||||
# define c_tolower(x) tolower ((unsigned char) (x))
|
||||
# ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
# else
|
||||
typedef unsigned long uintptr_t;
|
||||
# endif
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "hash.h"
|
||||
@@ -767,6 +763,15 @@ main (void)
|
||||
{
|
||||
struct hash_table *ht = make_string_hash_table (0);
|
||||
char line[80];
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
/* Set the current locale. */
|
||||
setlocale (LC_ALL, "");
|
||||
/* Set the text message domain. */
|
||||
bindtextdomain ("wget", LOCALEDIR);
|
||||
textdomain ("wget");
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
while ((fgets (line, sizeof (line), stdin)))
|
||||
{
|
||||
int len = strlen (line);
|
||||
|
||||
@@ -34,7 +34,7 @@ as that of the covered work. */
|
||||
struct hash_table;
|
||||
|
||||
struct hash_table *hash_table_new (int, unsigned long (*) (const void *),
|
||||
int (*) (const void *, const void *));
|
||||
int (*) (const void *, const void *));
|
||||
void hash_table_destroy (struct hash_table *);
|
||||
|
||||
void *hash_table_get (const struct hash_table *, const void *);
|
||||
@@ -47,11 +47,11 @@ int hash_table_remove (struct hash_table *, const void *);
|
||||
void hash_table_clear (struct hash_table *);
|
||||
|
||||
void hash_table_for_each (struct hash_table *,
|
||||
int (*) (void *, void *, void *), void *);
|
||||
int (*) (void *, void *, void *), void *);
|
||||
|
||||
typedef struct {
|
||||
void *key, *value; /* public members */
|
||||
void *pos, *end; /* private members */
|
||||
void *key, *value; /* public members */
|
||||
void *pos, *end; /* private members */
|
||||
} hash_table_iterator;
|
||||
void hash_table_iterate (struct hash_table *, hash_table_iterator *);
|
||||
int hash_table_iter_next (hash_table_iterator *);
|
||||
|
||||
@@ -58,9 +58,9 @@ typedef struct {
|
||||
|
||||
/* The actual data, in the form of struct in_addr or in6_addr: */
|
||||
union {
|
||||
struct in_addr d4; /* IPv4 address */
|
||||
struct in_addr d4; /* IPv4 address */
|
||||
#ifdef ENABLE_IPV6
|
||||
struct in6_addr d6; /* IPv6 address */
|
||||
struct in6_addr d6; /* IPv6 address */
|
||||
#endif
|
||||
} data;
|
||||
|
||||
|
||||
@@ -1189,6 +1189,14 @@ int main ()
|
||||
int read_count;
|
||||
int tag_counter = 0;
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
/* Set the current locale. */
|
||||
setlocale (LC_ALL, "");
|
||||
/* Set the text message domain. */
|
||||
bindtextdomain ("wget", LOCALEDIR);
|
||||
textdomain ("wget");
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
while ((read_count = fread (x + length, 1, size - length, stdin)))
|
||||
{
|
||||
length += read_count;
|
||||
|
||||
@@ -32,8 +32,8 @@ as that of the covered work. */
|
||||
#define HTML_PARSE_H
|
||||
|
||||
struct attr_pair {
|
||||
char *name; /* attribute name */
|
||||
char *value; /* attribute value */
|
||||
char *name; /* attribute name */
|
||||
char *value; /* attribute value */
|
||||
|
||||
/* Needed for URL conversion; the places where the value begins and
|
||||
ends, including the quotes and everything. */
|
||||
@@ -45,19 +45,19 @@ struct attr_pair {
|
||||
};
|
||||
|
||||
struct taginfo {
|
||||
char *name; /* tag name */
|
||||
int end_tag_p; /* whether this is an end-tag */
|
||||
int nattrs; /* number of attributes */
|
||||
struct attr_pair *attrs; /* attributes */
|
||||
char *name; /* tag name */
|
||||
int end_tag_p; /* whether this is an end-tag */
|
||||
int nattrs; /* number of attributes */
|
||||
struct attr_pair *attrs; /* attributes */
|
||||
|
||||
const char *start_position; /* start position of tag */
|
||||
const char *end_position; /* end position of tag */
|
||||
const char *start_position; /* start position of tag */
|
||||
const char *end_position; /* end position of tag */
|
||||
|
||||
const char *contents_begin; /* delimiters of tag contents */
|
||||
const char *contents_end; /* only valid if end_tag_p */
|
||||
};
|
||||
|
||||
struct hash_table; /* forward declaration */
|
||||
struct hash_table; /* forward declaration */
|
||||
|
||||
/* Flags for map_html_tags: */
|
||||
#define MHT_STRICT_COMMENTS 1 /* use strict comment interpretation */
|
||||
@@ -65,7 +65,7 @@ struct hash_table; /* forward declaration */
|
||||
<a href=" foo "> as "foo" */
|
||||
|
||||
void map_html_tags (const char *, int,
|
||||
void (*) (struct taginfo *, void *), void *, int,
|
||||
const struct hash_table *, const struct hash_table *);
|
||||
void (*) (struct taginfo *, void *), void *, int,
|
||||
const struct hash_table *, const struct hash_table *);
|
||||
|
||||
#endif /* HTML_PARSE_H */
|
||||
|
||||
@@ -79,7 +79,10 @@ enum {
|
||||
TAG_SCRIPT,
|
||||
TAG_TABLE,
|
||||
TAG_TD,
|
||||
TAG_TH
|
||||
TAG_TH,
|
||||
TAG_VIDEO,
|
||||
TAG_AUDIO,
|
||||
TAG_SOURCE
|
||||
};
|
||||
|
||||
/* The list of known tags and functions used for handling them. Most
|
||||
@@ -110,7 +113,10 @@ static struct known_tag {
|
||||
{ TAG_SCRIPT, "script", tag_find_urls },
|
||||
{ TAG_TABLE, "table", tag_find_urls },
|
||||
{ TAG_TD, "td", tag_find_urls },
|
||||
{ TAG_TH, "th", tag_find_urls }
|
||||
{ TAG_TH, "th", tag_find_urls },
|
||||
{ TAG_VIDEO, "video", tag_find_urls },
|
||||
{ TAG_AUDIO, "audio", tag_find_urls },
|
||||
{ TAG_SOURCE, "source", tag_find_urls }
|
||||
};
|
||||
|
||||
/* tag_url_attributes documents which attributes of which tags contain
|
||||
@@ -157,7 +163,12 @@ static struct {
|
||||
{ TAG_SCRIPT, "src", ATTR_INLINE },
|
||||
{ TAG_TABLE, "background", ATTR_INLINE },
|
||||
{ TAG_TD, "background", ATTR_INLINE },
|
||||
{ TAG_TH, "background", ATTR_INLINE }
|
||||
{ TAG_TH, "background", ATTR_INLINE },
|
||||
{ TAG_VIDEO, "src", ATTR_INLINE },
|
||||
{ TAG_VIDEO, "poster", ATTR_INLINE },
|
||||
{ TAG_AUDIO, "src", ATTR_INLINE },
|
||||
{ TAG_AUDIO, "poster", ATTR_INLINE },
|
||||
{ TAG_SOURCE, "src", ATTR_INLINE }
|
||||
};
|
||||
|
||||
/* The lists of interesting tags and attributes are built dynamically,
|
||||
@@ -273,6 +284,10 @@ append_url (const char *link_uri, int position, int size,
|
||||
const char *base = ctx->base ? ctx->base : ctx->parent_base;
|
||||
struct url *url;
|
||||
|
||||
struct iri *iri = iri_new ();
|
||||
set_uri_encoding (iri, opt.locale, true);
|
||||
iri->utf8_encode = true;
|
||||
|
||||
if (!base)
|
||||
{
|
||||
DEBUGP (("%s: no base, merge will use \"%s\".\n",
|
||||
@@ -290,7 +305,7 @@ append_url (const char *link_uri, int position, int size,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
url = url_parse (link_uri, NULL, NULL, false);
|
||||
url = url_parse (link_uri, NULL, iri, false);
|
||||
if (!url)
|
||||
{
|
||||
DEBUGP (("%s: link \"%s\" doesn't parse.\n",
|
||||
@@ -312,7 +327,7 @@ append_url (const char *link_uri, int position, int size,
|
||||
quote_n (2, link_uri),
|
||||
quotearg_n_style (3, escape_quoting_style, complete_uri)));
|
||||
|
||||
url = url_parse (complete_uri, NULL, NULL, false);
|
||||
url = url_parse (complete_uri, NULL, iri, false);
|
||||
if (!url)
|
||||
{
|
||||
DEBUGP (("%s: merged link \"%s\" doesn't parse.\n",
|
||||
@@ -323,6 +338,8 @@ append_url (const char *link_uri, int position, int size,
|
||||
xfree (complete_uri);
|
||||
}
|
||||
|
||||
iri_free (iri);
|
||||
|
||||
DEBUGP (("appending %s to urlpos.\n", quote (url->url)));
|
||||
|
||||
newel = xnew0 (struct urlpos);
|
||||
@@ -455,7 +472,7 @@ tag_find_urls (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
/* Handle the BASE tag, for <base href=...>. */
|
||||
|
||||
static void
|
||||
tag_handle_base (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
tag_handle_base (int tagid _GL_UNUSED, struct taginfo *tag, struct map_context *ctx)
|
||||
{
|
||||
struct urlpos *base_urlpos;
|
||||
int attrind;
|
||||
@@ -481,7 +498,7 @@ tag_handle_base (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
/* Mark the URL found in <form action=...> for conversion. */
|
||||
|
||||
static void
|
||||
tag_handle_form (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
tag_handle_form (int tagid _GL_UNUSED, struct taginfo *tag, struct map_context *ctx)
|
||||
{
|
||||
int attrind;
|
||||
char *action = find_attr (tag, "action", &attrind);
|
||||
@@ -499,7 +516,7 @@ tag_handle_form (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
links will be followed in -p mode depends on the REL attribute. */
|
||||
|
||||
static void
|
||||
tag_handle_link (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
tag_handle_link (int tagid _GL_UNUSED, struct taginfo *tag, struct map_context *ctx)
|
||||
{
|
||||
int attrind;
|
||||
char *href = find_attr (tag, "href", &attrind);
|
||||
@@ -548,7 +565,7 @@ tag_handle_link (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
refresh feature and because of robot exclusion. */
|
||||
|
||||
static void
|
||||
tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
tag_handle_meta (int tagid _GL_UNUSED, struct taginfo *tag, struct map_context *ctx)
|
||||
{
|
||||
char *name = find_attr (tag, "name", NULL);
|
||||
char *http_equiv = find_attr (tag, "http-equiv", NULL);
|
||||
@@ -804,6 +821,13 @@ get_urls_file (const char *file)
|
||||
url_text = merged;
|
||||
}
|
||||
|
||||
char *new_url = rewrite_shorthand_url (url_text);
|
||||
if (new_url)
|
||||
{
|
||||
xfree (url_text);
|
||||
url_text = new_url;
|
||||
}
|
||||
|
||||
url = url_parse (url_text, &up_error_code, NULL, false);
|
||||
if (!url)
|
||||
{
|
||||
@@ -830,7 +854,7 @@ get_urls_file (const char *file)
|
||||
return head;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
cleanup_html_url (void)
|
||||
{
|
||||
/* Destroy the hash tables. The hash table keys and values are not
|
||||
|
||||
@@ -32,20 +32,21 @@ as that of the covered work. */
|
||||
#define HTML_URL_H
|
||||
|
||||
struct map_context {
|
||||
char *text; /* HTML text. */
|
||||
char *base; /* Base URI of the document, possibly
|
||||
changed through <base href=...>. */
|
||||
const char *parent_base; /* Base of the current document. */
|
||||
const char *document_file; /* File name of this document. */
|
||||
bool nofollow; /* whether NOFOLLOW was specified in a
|
||||
char *text; /* HTML text. */
|
||||
char *base; /* Base URI of the document, possibly
|
||||
changed through <base href=...>. */
|
||||
const char *parent_base; /* Base of the current document. */
|
||||
const char *document_file; /* File name of this document. */
|
||||
bool nofollow; /* whether NOFOLLOW was specified in a
|
||||
<meta name=robots> tag. */
|
||||
|
||||
struct urlpos *head; /* List of URLs that is being built. */
|
||||
struct urlpos *head; /* List of URLs that is being built. */
|
||||
};
|
||||
|
||||
struct urlpos *get_urls_file (const char *);
|
||||
struct urlpos *get_urls_html (const char *, const char *, bool *, struct iri *);
|
||||
struct urlpos *append_url (const char *, int, int, struct map_context *);
|
||||
void free_urlpos (struct urlpos *);
|
||||
void cleanup_html_url (void);
|
||||
|
||||
#endif /* HTML_URL_H */
|
||||
|
||||
174
src/http-ntlm.c
174
src/http-ntlm.c
@@ -42,67 +42,44 @@ as that of the covered work. */
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "http-ntlm.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x00907001L
|
||||
#define DES_key_schedule des_key_schedule
|
||||
#define DES_cblock des_cblock
|
||||
#define DES_set_odd_parity des_set_odd_parity
|
||||
#define DES_set_key des_set_key
|
||||
#define DES_ecb_encrypt des_ecb_encrypt
|
||||
#ifdef HAVE_NETTLE
|
||||
# include <nettle/md4.h>
|
||||
# include <nettle/des.h>
|
||||
#else
|
||||
# include <openssl/des.h>
|
||||
# include <openssl/md4.h>
|
||||
# include <openssl/opensslv.h>
|
||||
|
||||
# if OPENSSL_VERSION_NUMBER < 0x00907001L
|
||||
# define DES_key_schedule des_key_schedule
|
||||
# define DES_cblock des_cblock
|
||||
# define DES_set_odd_parity des_set_odd_parity
|
||||
# define DES_set_key des_set_key
|
||||
# define DES_ecb_encrypt des_ecb_encrypt
|
||||
|
||||
/* This is how things were done in the old days */
|
||||
#define DESKEY(x) x
|
||||
#define DESKEYARG(x) x
|
||||
#else
|
||||
# define DESKEY(x) x
|
||||
# define DESKEYARG(x) x
|
||||
# else
|
||||
/* Modern version */
|
||||
#define DESKEYARG(x) *x
|
||||
#define DESKEY(x) &x
|
||||
# define DESKEYARG(x) *x
|
||||
# define DESKEY(x) &x
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Define this to make the type-3 message include the NT response message */
|
||||
#define USE_NTRESPONSES 1
|
||||
|
||||
|
||||
/* Flag bits definitions available at on
|
||||
http://davenport.sourceforge.net/ntlm.html */
|
||||
|
||||
#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
|
||||
#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
|
||||
#define NTLMFLAG_REQUEST_TARGET (1<<2)
|
||||
/* unknown (1<<3) */
|
||||
#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
|
||||
#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
|
||||
#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
|
||||
#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
|
||||
#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
|
||||
#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
|
||||
/* unknown (1<<10) */
|
||||
/* unknown (1<<11) */
|
||||
#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
|
||||
#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
|
||||
#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
|
||||
#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
|
||||
#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
|
||||
#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
|
||||
#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
|
||||
#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
|
||||
#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
|
||||
#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
|
||||
#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
|
||||
#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
|
||||
/* unknown (1<24) */
|
||||
/* unknown (1<25) */
|
||||
/* unknown (1<26) */
|
||||
/* unknown (1<27) */
|
||||
/* unknown (1<28) */
|
||||
#define NTLMFLAG_NEGOTIATE_128 (1<<29)
|
||||
#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
|
||||
#define NTLMFLAG_NEGOTIATE_56 (1<<31)
|
||||
|
||||
/*
|
||||
(*) = A "security buffer" is a triplet consisting of two shorts and one
|
||||
@@ -140,7 +117,7 @@ ntlm_input (struct ntlmdata *ntlm, const char *header)
|
||||
(40) Target Information (optional) security buffer(*)
|
||||
32 (48) start of data block
|
||||
*/
|
||||
int size;
|
||||
ssize_t size;
|
||||
char *buffer = (char *) alloca (strlen (header));
|
||||
|
||||
DEBUGP (("Received a type-2 NTLM message.\n"));
|
||||
@@ -176,6 +153,25 @@ ntlm_input (struct ntlmdata *ntlm, const char *header)
|
||||
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
|
||||
* key schedule ks is also set.
|
||||
*/
|
||||
#ifdef HAVE_NETTLE
|
||||
static void
|
||||
setup_des_key(unsigned char *key_56,
|
||||
struct des_ctx *des)
|
||||
{
|
||||
unsigned char key[8];
|
||||
|
||||
key[0] = key_56[0];
|
||||
key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
|
||||
key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
|
||||
key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
|
||||
key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
|
||||
key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
|
||||
key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
|
||||
key[7] = (key_56[6] << 1) & 0xFF;
|
||||
|
||||
nettle_des_set_key(des, key);
|
||||
}
|
||||
#else
|
||||
static void
|
||||
setup_des_key(unsigned char *key_56,
|
||||
DES_key_schedule DESKEYARG(ks))
|
||||
@@ -194,6 +190,7 @@ setup_des_key(unsigned char *key_56,
|
||||
DES_set_odd_parity(&key);
|
||||
DES_set_key(&key, ks);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
|
||||
@@ -203,6 +200,18 @@ setup_des_key(unsigned char *key_56,
|
||||
static void
|
||||
calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
|
||||
{
|
||||
#ifdef HAVE_NETTLE
|
||||
struct des_ctx des;
|
||||
|
||||
setup_des_key(keys, &des);
|
||||
nettle_des_encrypt(&des, 8, results, plaintext);
|
||||
|
||||
setup_des_key(keys + 7, &des);
|
||||
nettle_des_encrypt(&des, 8, results + 8, plaintext);
|
||||
|
||||
setup_des_key(keys + 14, &des);
|
||||
nettle_des_encrypt(&des, 8, results + 16, plaintext);
|
||||
#else
|
||||
DES_key_schedule ks;
|
||||
|
||||
setup_des_key(keys, DESKEY(ks));
|
||||
@@ -216,6 +225,7 @@ calc_resp(unsigned char *keys, unsigned char *plaintext, unsigned char *results)
|
||||
setup_des_key(keys+14, DESKEY(ks));
|
||||
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
|
||||
DESKEY(ks), DES_ENCRYPT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -238,8 +248,7 @@ mkhash(const char *password,
|
||||
static const unsigned char magic[] = {
|
||||
0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
|
||||
};
|
||||
int i;
|
||||
int len = strlen(password);
|
||||
size_t i, len = strlen(password);
|
||||
|
||||
/* make it fit at least 14 bytes */
|
||||
pw = (unsigned char *) alloca (len < 7 ? 14 : len * 2);
|
||||
@@ -248,13 +257,22 @@ mkhash(const char *password,
|
||||
len = 14;
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
pw[i] = c_toupper (password[i]);
|
||||
pw[i] = (unsigned char) c_toupper (password[i]);
|
||||
|
||||
for (; i<14; i++)
|
||||
pw[i] = 0;
|
||||
|
||||
{
|
||||
/* create LanManager hashed password */
|
||||
#ifdef HAVE_NETTLE
|
||||
struct des_ctx des;
|
||||
|
||||
setup_des_key(pw, &des);
|
||||
nettle_des_encrypt(&des, 8, lmbuffer, magic);
|
||||
|
||||
setup_des_key(pw + 7, &des);
|
||||
nettle_des_encrypt(&des, 8, lmbuffer + 8, magic);
|
||||
#else
|
||||
DES_key_schedule ks;
|
||||
|
||||
setup_des_key(pw, DESKEY(ks));
|
||||
@@ -264,6 +282,7 @@ mkhash(const char *password,
|
||||
setup_des_key(pw+7, DESKEY(ks));
|
||||
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
|
||||
DESKEY(ks), DES_ENCRYPT);
|
||||
#endif
|
||||
|
||||
memset(lmbuffer+16, 0, 5);
|
||||
}
|
||||
@@ -272,19 +291,29 @@ mkhash(const char *password,
|
||||
|
||||
#ifdef USE_NTRESPONSES
|
||||
{
|
||||
/* create NT hashed password */
|
||||
#ifdef HAVE_NETTLE
|
||||
struct md4_ctx MD4;
|
||||
#else
|
||||
MD4_CTX MD4;
|
||||
#endif
|
||||
|
||||
len = strlen(password);
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
pw[2*i] = password[i];
|
||||
pw[2*i] = (unsigned char) password[i];
|
||||
pw[2*i+1] = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_NETTLE
|
||||
nettle_md4_init(&MD4);
|
||||
nettle_md4_update(&MD4, (unsigned) (2 * len), pw);
|
||||
nettle_md4_digest(&MD4, MD4_DIGEST_SIZE, ntbuffer);
|
||||
#else
|
||||
/* create NT hashed password */
|
||||
MD4_Init(&MD4);
|
||||
MD4_Update(&MD4, pw, 2*len);
|
||||
MD4_Final(ntbuffer, &MD4);
|
||||
#endif
|
||||
|
||||
memset(ntbuffer+16, 0, 5);
|
||||
}
|
||||
@@ -293,7 +322,7 @@ mkhash(const char *password,
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
|
||||
#define SHORTPAIR(x) (char) ((x) & 0xff), (char) ((x) >> 8)
|
||||
#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
|
||||
(((x) >>16)&0xff), ((x)>>24)
|
||||
|
||||
@@ -302,19 +331,19 @@ char *
|
||||
ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
bool *ready)
|
||||
{
|
||||
const char *domain=""; /* empty */
|
||||
const char *host=""; /* empty */
|
||||
int domlen=strlen(domain);
|
||||
int hostlen = strlen(host);
|
||||
int hostoff; /* host name offset */
|
||||
int domoff; /* domain name offset */
|
||||
int size;
|
||||
const char *domain = ""; /* empty */
|
||||
const char *host = ""; /* empty */
|
||||
size_t domlen = strlen(domain);
|
||||
size_t hostlen = strlen(host);
|
||||
size_t hostoff; /* host name offset */
|
||||
size_t domoff; /* domain name offset */
|
||||
size_t size;
|
||||
char *base64;
|
||||
char ntlmbuf[256]; /* enough, unless the host/domain is very long */
|
||||
|
||||
/* point to the address of the pointer that holds the string to sent to the
|
||||
server, which is for a plain host or for a HTTP proxy */
|
||||
char *output;
|
||||
char *output = NULL;
|
||||
|
||||
*ready = false;
|
||||
|
||||
@@ -327,7 +356,8 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
|
||||
switch(ntlm->state) {
|
||||
case NTLMSTATE_TYPE1:
|
||||
default: /* for the weird cases we (re)start here */
|
||||
case NTLMSTATE_NONE:
|
||||
case NTLMSTATE_LAST:
|
||||
hostoff = 32;
|
||||
domoff = hostoff + hostlen;
|
||||
|
||||
@@ -405,15 +435,15 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
*/
|
||||
|
||||
{
|
||||
int lmrespoff;
|
||||
int ntrespoff;
|
||||
int useroff;
|
||||
size_t lmrespoff;
|
||||
size_t ntrespoff;
|
||||
size_t useroff;
|
||||
unsigned char lmresp[0x18]; /* fixed-size */
|
||||
#ifdef USE_NTRESPONSES
|
||||
unsigned char ntresp[0x18]; /* fixed-size */
|
||||
#endif
|
||||
const char *usr;
|
||||
int userlen;
|
||||
size_t userlen;
|
||||
|
||||
DEBUGP (("Creating a type-3 NTLM message.\n"));
|
||||
|
||||
@@ -423,7 +453,7 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
|
||||
if (usr) {
|
||||
domain = user;
|
||||
domlen = usr - domain;
|
||||
domlen = (size_t) (usr - domain);
|
||||
usr++;
|
||||
}
|
||||
else
|
||||
@@ -444,7 +474,7 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
|
||||
/* Create the big type-3 message binary blob */
|
||||
|
||||
size = snprintf (ntlmbuf, sizeof(ntlmbuf),
|
||||
size = (size_t) snprintf (ntlmbuf, sizeof(ntlmbuf),
|
||||
"NTLMSSP%c"
|
||||
"\x03%c%c%c" /* type-3, 32 bits */
|
||||
|
||||
@@ -527,7 +557,7 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
|
||||
/* Make sure that the user and domain strings fit in the target buffer
|
||||
before we copy them there. */
|
||||
if(((size_t) size + userlen + domlen) >= sizeof(ntlmbuf))
|
||||
if((size + userlen + domlen) >= sizeof(ntlmbuf))
|
||||
return NULL;
|
||||
|
||||
memcpy(&ntlmbuf[size], domain, domlen);
|
||||
@@ -537,20 +567,20 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
size += userlen;
|
||||
|
||||
/* we append the binary hashes to the end of the blob */
|
||||
if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
|
||||
if(size < (sizeof(ntlmbuf) - 0x18)) {
|
||||
memcpy(&ntlmbuf[size], lmresp, 0x18);
|
||||
size += 0x18;
|
||||
}
|
||||
|
||||
#ifdef USE_NTRESPONSES
|
||||
if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
|
||||
if(size < (sizeof(ntlmbuf) - 0x18)) {
|
||||
memcpy(&ntlmbuf[size], ntresp, 0x18);
|
||||
size += 0x18;
|
||||
}
|
||||
#endif
|
||||
|
||||
ntlmbuf[56] = size & 0xff;
|
||||
ntlmbuf[57] = size >> 8;
|
||||
ntlmbuf[56] = (char) (size & 0xff);
|
||||
ntlmbuf[57] = (char) (size >> 8);
|
||||
|
||||
/* convert the binary blob into base64 */
|
||||
base64 = (char *) alloca (BASE64_LENGTH (size) + 1);
|
||||
|
||||
908
src/http.c
908
src/http.c
File diff suppressed because it is too large
Load Diff
@@ -31,10 +31,12 @@ as that of the covered work. */
|
||||
#ifndef HTTP_H
|
||||
#define HTTP_H
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
struct url;
|
||||
|
||||
uerr_t http_loop (struct url *, struct url *, char **, char **, const char *,
|
||||
int *, struct url *, struct iri *);
|
||||
int *, struct url *, struct iri *, struct range *);
|
||||
void save_cookies (void);
|
||||
void http_cleanup (void);
|
||||
time_t http_atotm (const char *);
|
||||
@@ -43,7 +45,7 @@ typedef struct {
|
||||
/* A token consists of characters in the [b, e) range. */
|
||||
const char *b, *e;
|
||||
} param_token;
|
||||
bool extract_param (const char **, param_token *, param_token *, char);
|
||||
bool extract_param (const char **, param_token *, param_token *, char, bool *);
|
||||
|
||||
|
||||
#endif /* HTTP_H */
|
||||
|
||||
195
src/init.c
195
src/init.c
@@ -1,6 +1,6 @@
|
||||
/* Reading/parsing the initialization file.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -68,6 +68,7 @@ as that of the covered work. */
|
||||
#include "http.h" /* for http_cleanup */
|
||||
#include "retr.h" /* for output_stream */
|
||||
#include "warc.h" /* for warc_close */
|
||||
#include "spider.h" /* for spider_cleanup */
|
||||
|
||||
#ifdef TESTING
|
||||
#include "test.h"
|
||||
@@ -87,6 +88,7 @@ CMD_DECLARE (cmd_directory_vector);
|
||||
CMD_DECLARE (cmd_number);
|
||||
CMD_DECLARE (cmd_number_inf);
|
||||
CMD_DECLARE (cmd_string);
|
||||
CMD_DECLARE (cmd_string_uppercase);
|
||||
CMD_DECLARE (cmd_file);
|
||||
CMD_DECLARE (cmd_directory);
|
||||
CMD_DECLARE (cmd_time);
|
||||
@@ -136,6 +138,8 @@ static const struct {
|
||||
{ "backups", &opt.backups, cmd_number },
|
||||
{ "base", &opt.base_href, cmd_string },
|
||||
{ "bindaddress", &opt.bind_address, cmd_string },
|
||||
{ "bodydata", &opt.body_data, cmd_string },
|
||||
{ "bodyfile", &opt.body_file, cmd_string },
|
||||
#ifdef HAVE_SSL
|
||||
{ "cacertificate", &opt.ca_cert, cmd_file },
|
||||
#endif
|
||||
@@ -146,7 +150,7 @@ static const struct {
|
||||
{ "certificatetype", &opt.cert_type, cmd_cert_type },
|
||||
{ "checkcertificate", &opt.check_cert, cmd_boolean },
|
||||
#endif
|
||||
{ "chooseconfig", &opt.choose_config, cmd_file },
|
||||
{ "chooseconfig", &opt.choose_config, cmd_file },
|
||||
{ "connecttimeout", &opt.connect_timeout, cmd_time },
|
||||
{ "contentdisposition", &opt.content_disposition, cmd_boolean },
|
||||
{ "contentonerror", &opt.content_on_error, cmd_boolean },
|
||||
@@ -154,10 +158,8 @@ static const struct {
|
||||
{ "convertlinks", &opt.convert_links, cmd_boolean },
|
||||
{ "cookies", &opt.cookies, cmd_boolean },
|
||||
{ "cutdirs", &opt.cut_dirs, cmd_number },
|
||||
#ifdef ENABLE_DEBUG
|
||||
{ "debug", &opt.debug, cmd_boolean },
|
||||
#endif
|
||||
{ "defaultpage", &opt.default_page, cmd_string},
|
||||
{ "defaultpage", &opt.default_page, cmd_string },
|
||||
{ "deleteafter", &opt.delete_after, cmd_boolean },
|
||||
{ "dirprefix", &opt.dir_prefix, cmd_directory },
|
||||
{ "dirstruct", NULL, cmd_spec_dirstruct },
|
||||
@@ -191,6 +193,9 @@ static const struct {
|
||||
{ "httppasswd", &opt.http_passwd, cmd_string }, /* deprecated */
|
||||
{ "httppassword", &opt.http_passwd, cmd_string },
|
||||
{ "httpproxy", &opt.http_proxy, cmd_string },
|
||||
#ifdef HAVE_SSL
|
||||
{ "httpsonly", &opt.https_only, cmd_boolean },
|
||||
#endif
|
||||
{ "httpsproxy", &opt.https_proxy, cmd_string },
|
||||
{ "httpuser", &opt.http_user, cmd_string },
|
||||
{ "ignorecase", &opt.ignore_case, cmd_boolean },
|
||||
@@ -203,6 +208,9 @@ static const struct {
|
||||
#endif
|
||||
{ "input", &opt.input_filename, cmd_file },
|
||||
{ "iri", &opt.enable_iri, cmd_boolean },
|
||||
#ifdef ENABLE_THREADS
|
||||
{ "jobs", &opt.jobs, cmd_number },
|
||||
#endif
|
||||
{ "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
|
||||
{ "limitrate", &opt.limit_rate, cmd_bytes },
|
||||
{ "loadcookies", &opt.cookies_input, cmd_file },
|
||||
@@ -210,9 +218,14 @@ static const struct {
|
||||
{ "logfile", &opt.lfilename, cmd_file },
|
||||
{ "login", &opt.ftp_user, cmd_string },/* deprecated*/
|
||||
{ "maxredirect", &opt.max_redirect, cmd_number },
|
||||
#ifdef ENABLE_METALINK
|
||||
{ "metalink", &opt.metalink_file, cmd_file },
|
||||
#endif
|
||||
{ "method", &opt.method, cmd_string_uppercase },
|
||||
{ "mirror", NULL, cmd_spec_mirror },
|
||||
{ "netrc", &opt.netrc, cmd_boolean },
|
||||
{ "noclobber", &opt.noclobber, cmd_boolean },
|
||||
{ "noconfig", &opt.noconfig, cmd_boolean },
|
||||
{ "noparent", &opt.no_parent, cmd_boolean },
|
||||
{ "noproxy", &opt.no_proxy, cmd_vector },
|
||||
{ "numtries", &opt.ntry, cmd_number_inf },/* deprecated*/
|
||||
@@ -252,6 +265,9 @@ static const struct {
|
||||
{ "removelisting", &opt.remove_listing, cmd_boolean },
|
||||
{ "reportspeed", &opt.report_bps, cmd_spec_report_speed},
|
||||
{ "restrictfilenames", NULL, cmd_spec_restrict_file_names },
|
||||
#ifdef ENABLE_METALINK
|
||||
{ "retries", &opt.n_retries, cmd_number_inf },
|
||||
#endif
|
||||
{ "retrsymlinks", &opt.retr_symlinks, cmd_boolean },
|
||||
{ "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
|
||||
{ "robots", &opt.use_robots, cmd_boolean },
|
||||
@@ -262,8 +278,10 @@ static const struct {
|
||||
#endif
|
||||
{ "serverresponse", &opt.server_response, cmd_boolean },
|
||||
{ "showalldnsentries", &opt.show_all_dns_entries, cmd_boolean },
|
||||
{ "showprogress", &opt.show_progress, cmd_boolean },
|
||||
{ "spanhosts", &opt.spanhost, cmd_boolean },
|
||||
{ "spider", &opt.spider, cmd_boolean },
|
||||
{ "startpos", &opt.start_pos, cmd_bytes },
|
||||
{ "strictcomments", &opt.strict_comments, cmd_boolean },
|
||||
{ "timeout", NULL, cmd_spec_timeout },
|
||||
{ "timestamping", &opt.timestamping, cmd_boolean },
|
||||
@@ -333,6 +351,12 @@ defaults (void)
|
||||
opt.cookies = true;
|
||||
opt.verbose = -1;
|
||||
opt.ntry = 20;
|
||||
#ifdef ENABLE_THREADS
|
||||
opt.jobs = 1;
|
||||
#endif
|
||||
#ifdef ENABLE_METALINK
|
||||
opt.n_retries = 1;
|
||||
#endif
|
||||
opt.reclevel = 5;
|
||||
opt.add_hostdir = true;
|
||||
opt.netrc = true;
|
||||
@@ -400,6 +424,11 @@ defaults (void)
|
||||
opt.warc_cdx_dedup_filename = NULL;
|
||||
opt.warc_tempdir = NULL;
|
||||
opt.warc_keep_log = true;
|
||||
|
||||
/* Use a negative value to mark the absence of --start-pos option */
|
||||
opt.start_pos = -1;
|
||||
opt.show_progress = false;
|
||||
opt.noscroll = false;
|
||||
}
|
||||
|
||||
/* Return the user's home directory (strdup-ed), or NULL if none is
|
||||
@@ -431,12 +460,7 @@ home_dir (void)
|
||||
assert (p);
|
||||
|
||||
len = p - buff + 1;
|
||||
buff = malloc (len + 1);
|
||||
if (buff == NULL)
|
||||
return NULL;
|
||||
|
||||
strncpy (buff, _w32_get_argv0 (), len);
|
||||
buff[len] = '\0';
|
||||
buff = strdup (_w32_get_argv0 ());
|
||||
|
||||
home = buf;
|
||||
#elif !defined(WINDOWS)
|
||||
@@ -455,8 +479,7 @@ home_dir (void)
|
||||
}
|
||||
|
||||
ret = home ? xstrdup (home) : NULL;
|
||||
if (buf)
|
||||
free (buf);
|
||||
free (buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -475,7 +498,7 @@ wgetrc_env_file_name (void)
|
||||
{
|
||||
fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
|
||||
exec_name, env);
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
return xstrdup (env);
|
||||
}
|
||||
@@ -570,7 +593,8 @@ bool
|
||||
run_wgetrc (const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line;
|
||||
char *line = NULL;
|
||||
size_t bufsize = 0;
|
||||
int ln;
|
||||
int errcnt = 0;
|
||||
|
||||
@@ -582,7 +606,7 @@ run_wgetrc (const char *file)
|
||||
return true; /* not a fatal error */
|
||||
}
|
||||
ln = 1;
|
||||
while ((line = read_whole_line (fp)) != NULL)
|
||||
while (getline (&line, &bufsize, fp) > 0)
|
||||
{
|
||||
char *com = NULL, *val = NULL;
|
||||
int comind;
|
||||
@@ -616,9 +640,9 @@ run_wgetrc (const char *file)
|
||||
}
|
||||
xfree_null (com);
|
||||
xfree_null (val);
|
||||
xfree (line);
|
||||
++ln;
|
||||
}
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
|
||||
return errcnt == 0;
|
||||
@@ -646,7 +670,7 @@ initialize (void)
|
||||
Parsing system wgetrc file (env SYSTEM_WGETRC) failed. Please check\n\
|
||||
'%s',\n\
|
||||
or specify a different file using --config.\n"), env_sysrc);
|
||||
exit (2);
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
}
|
||||
}
|
||||
/* Otherwise, if SYSTEM_WGETRC is defined, use it. */
|
||||
@@ -661,7 +685,7 @@ or specify a different file using --config.\n"), env_sysrc);
|
||||
Parsing system wgetrc file failed. Please check\n\
|
||||
'%s',\n\
|
||||
or specify a different file using --config.\n"), SYSTEM_WGETRC);
|
||||
exit (2);
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
}
|
||||
#endif
|
||||
/* Override it with your own, if one exists. */
|
||||
@@ -683,7 +707,7 @@ or specify a different file using --config.\n"), SYSTEM_WGETRC);
|
||||
|
||||
/* If there were errors processing either `.wgetrc', abort. */
|
||||
if (!ok)
|
||||
exit (2);
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
|
||||
xfree (file);
|
||||
return;
|
||||
@@ -807,16 +831,16 @@ setval_internal_tilde (int comind, const char *com, const char *val)
|
||||
pstring = commands[comind].place;
|
||||
home = home_dir ();
|
||||
if (home)
|
||||
{
|
||||
homelen = strlen (home);
|
||||
while (homelen && ISSEP (home[homelen - 1]))
|
||||
home[--homelen] = '\0';
|
||||
{
|
||||
homelen = strlen (home);
|
||||
while (homelen && ISSEP (home[homelen - 1]))
|
||||
home[--homelen] = '\0';
|
||||
|
||||
/* Skip the leading "~/". */
|
||||
for (++val; ISSEP (*val); val++)
|
||||
;
|
||||
*pstring = concat_strings (home, "/", val, (char *)0);
|
||||
}
|
||||
/* Skip the leading "~/". */
|
||||
for (++val; ISSEP (*val); val++)
|
||||
;
|
||||
*pstring = concat_strings (home, "/", val, (char *)0);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -824,8 +848,8 @@ setval_internal_tilde (int comind, const char *com, const char *val)
|
||||
/* Run command COM with value VAL. If running the command produces an
|
||||
error, report the error and exit.
|
||||
|
||||
This is intended to be called from main() to modify Wget's behavior
|
||||
through command-line switches. Since COM is hard-coded in main(),
|
||||
This is intended to be called from main to modify Wget's behavior
|
||||
through command-line switches. Since COM is hard-coded in main,
|
||||
it is not canonicalized, and this aborts when COM is not found.
|
||||
|
||||
If COMIND's are exported to init.h, this function will be changed
|
||||
@@ -842,7 +866,7 @@ setoptval (const char *com, const char *val, const char *optname)
|
||||
|
||||
assert (val != NULL);
|
||||
if (!setval_internal (command_by_name (com), dd_optname, val))
|
||||
exit (2);
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
}
|
||||
|
||||
/* Parse OPT into command and value and run it. For example,
|
||||
@@ -850,22 +874,22 @@ setoptval (const char *com, const char *val, const char *optname)
|
||||
This is used by the `--execute' flag in main.c. */
|
||||
|
||||
void
|
||||
run_command (const char *opt)
|
||||
run_command (const char *cmdopt)
|
||||
{
|
||||
char *com, *val;
|
||||
int comind;
|
||||
switch (parse_line (opt, &com, &val, &comind))
|
||||
switch (parse_line (cmdopt, &com, &val, &comind))
|
||||
{
|
||||
case line_ok:
|
||||
if (!setval_internal (comind, com, val))
|
||||
exit (2);
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
xfree (com);
|
||||
xfree (val);
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, _("%s: Invalid --execute command %s\n"),
|
||||
exec_name, quote (opt));
|
||||
exit (2);
|
||||
exec_name, quote (cmdopt));
|
||||
exit (WGET_EXIT_PARSE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,7 +971,7 @@ cmd_number_inf (const char *com, const char *val, void *place)
|
||||
/* Copy (strdup) the string at COM to a new location and place a
|
||||
pointer to *PLACE. */
|
||||
static bool
|
||||
cmd_string (const char *com, const char *val, void *place)
|
||||
cmd_string (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
char **pstring = (char **)place;
|
||||
|
||||
@@ -956,12 +980,29 @@ cmd_string (const char *com, const char *val, void *place)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Like cmd_string but ensure the string is upper case. */
|
||||
static bool
|
||||
cmd_string_uppercase (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
char *q, **pstring;
|
||||
pstring = (char **)place;
|
||||
xfree_null (*pstring);
|
||||
|
||||
/* Like the above, but handles tilde-expansion when reading a user's
|
||||
*pstring = xmalloc (strlen (val) + 1);
|
||||
|
||||
for (q = *pstring; *val; val++, q++)
|
||||
*q = c_toupper (*val);
|
||||
|
||||
*q = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Like cmd_string, but handles tilde-expansion when reading a user's
|
||||
`.wgetrc'. In that case, and if VAL begins with `~', the tilde
|
||||
gets expanded to the user's home directory. */
|
||||
static bool
|
||||
cmd_file (const char *com, const char *val, void *place)
|
||||
cmd_file (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
char **pstring = (char **)place;
|
||||
|
||||
@@ -1008,7 +1049,7 @@ cmd_directory (const char *com, const char *val, void *place)
|
||||
PLACE vector is cleared instead. */
|
||||
|
||||
static bool
|
||||
cmd_vector (const char *com, const char *val, void *place)
|
||||
cmd_vector (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
char ***pvec = (char ***)place;
|
||||
|
||||
@@ -1023,7 +1064,7 @@ cmd_vector (const char *com, const char *val, void *place)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_directory_vector (const char *com, const char *val, void *place)
|
||||
cmd_directory_vector (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
char ***pvec = (char ***)place;
|
||||
|
||||
@@ -1239,7 +1280,7 @@ cmd_cert_type (const char *com, const char *val, void *place)
|
||||
static bool check_user_specified_header (const char *);
|
||||
|
||||
static bool
|
||||
cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
if (!cmd_boolean (com, val, &opt.dirstruct))
|
||||
return false;
|
||||
@@ -1253,7 +1294,7 @@ cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_header (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_header (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
/* Empty value means reset the list of headers. */
|
||||
if (*val == '\0')
|
||||
@@ -1274,7 +1315,7 @@ cmd_spec_header (const char *com, const char *val, void *place_ignored)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_warc_header (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_warc_header (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
/* Empty value means reset the list of headers. */
|
||||
if (*val == '\0')
|
||||
@@ -1295,7 +1336,7 @@ cmd_spec_warc_header (const char *com, const char *val, void *place_ignored)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_htmlify (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
int flag = cmd_boolean (com, val, &opt.htmlify);
|
||||
if (flag && !opt.htmlify)
|
||||
@@ -1307,7 +1348,7 @@ cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
|
||||
no limit on max. recursion depth, and don't remove listings. */
|
||||
|
||||
static bool
|
||||
cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_mirror (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
int mirror;
|
||||
|
||||
@@ -1329,7 +1370,7 @@ cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
|
||||
"IPv4", "IPv6", and "none". */
|
||||
|
||||
static bool
|
||||
cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
static const struct decode_item choices[] = {
|
||||
{ "IPv4", prefer_ipv4 },
|
||||
@@ -1348,7 +1389,7 @@ cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
|
||||
implementation before that. */
|
||||
|
||||
static bool
|
||||
cmd_spec_progress (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_progress (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
if (!valid_progress_implementation_p (val))
|
||||
{
|
||||
@@ -1359,7 +1400,7 @@ cmd_spec_progress (const char *com, const char *val, void *place_ignored)
|
||||
xfree_null (opt.progress_type);
|
||||
|
||||
/* Don't call set_progress_implementation here. It will be called
|
||||
in main() when it becomes clear what the log output is. */
|
||||
in main when it becomes clear what the log output is. */
|
||||
opt.progress_type = xstrdup (val);
|
||||
return true;
|
||||
}
|
||||
@@ -1369,7 +1410,7 @@ cmd_spec_progress (const char *com, const char *val, void *place_ignored)
|
||||
is specified. */
|
||||
|
||||
static bool
|
||||
cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_recursive (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
if (!cmd_boolean (com, val, &opt.recursive))
|
||||
return false;
|
||||
@@ -1384,7 +1425,7 @@ cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
|
||||
/* Validate --regex-type and set the choice. */
|
||||
|
||||
static bool
|
||||
cmd_spec_regex_type (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_regex_type (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
static const struct decode_item choices[] = {
|
||||
{ "posix", regex_type_posix },
|
||||
@@ -1401,7 +1442,7 @@ cmd_spec_regex_type (const char *com, const char *val, void *place_ignored)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
int restrict_os = opt.restrict_files_os;
|
||||
int restrict_ctrl = opt.restrict_files_ctrl;
|
||||
@@ -1455,7 +1496,7 @@ cmd_spec_restrict_file_names (const char *com, const char *val, void *place_igno
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_report_speed (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_report_speed (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
opt.report_bps = strcasecmp (val, "bits") == 0;
|
||||
if (!opt.report_bps)
|
||||
@@ -1472,6 +1513,7 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place)
|
||||
{ "sslv2", secure_protocol_sslv2 },
|
||||
{ "sslv3", secure_protocol_sslv3 },
|
||||
{ "tlsv1", secure_protocol_tlsv1 },
|
||||
{ "pfs", secure_protocol_pfs },
|
||||
};
|
||||
int ok = decode_string (val, choices, countof (choices), place);
|
||||
if (!ok)
|
||||
@@ -1483,7 +1525,7 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place)
|
||||
/* Set all three timeout values. */
|
||||
|
||||
static bool
|
||||
cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_timeout (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
double value;
|
||||
if (!cmd_time (com, val, &value))
|
||||
@@ -1495,7 +1537,7 @@ cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
|
||||
}
|
||||
|
||||
static bool
|
||||
cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_useragent (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
/* Disallow embedded newlines. */
|
||||
if (strchr (val, '\n'))
|
||||
@@ -1514,7 +1556,7 @@ cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
|
||||
some random hackery for disallowing -q -v). */
|
||||
|
||||
static bool
|
||||
cmd_spec_verbose (const char *com, const char *val, void *place_ignored)
|
||||
cmd_spec_verbose (const char *com, const char *val, void *place_ignored _GL_UNUSED)
|
||||
{
|
||||
bool flag;
|
||||
if (cmd_boolean (com, val, &flag))
|
||||
@@ -1667,10 +1709,6 @@ decode_string (const char *val, const struct decode_item *items, int itemcount,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void cleanup_html_url (void);
|
||||
|
||||
|
||||
/* Free the memory allocated by global variables. */
|
||||
void
|
||||
cleanup (void)
|
||||
@@ -1703,16 +1741,14 @@ cleanup (void)
|
||||
res_cleanup ();
|
||||
http_cleanup ();
|
||||
cleanup_html_url ();
|
||||
spider_cleanup ();
|
||||
host_cleanup ();
|
||||
log_cleanup ();
|
||||
netrc_cleanup (netrc_list);
|
||||
|
||||
for (i = 0; i < nurl; i++)
|
||||
xfree (url[i]);
|
||||
|
||||
{
|
||||
extern acc_t *netrc_list;
|
||||
free_netrc (netrc_list);
|
||||
}
|
||||
xfree_null (opt.choose_config);
|
||||
xfree_null (opt.lfilename);
|
||||
xfree_null (opt.dir_prefix);
|
||||
@@ -1752,6 +1788,7 @@ cleanup (void)
|
||||
xfree_null (opt.user);
|
||||
xfree_null (opt.passwd);
|
||||
xfree_null (opt.base_href);
|
||||
xfree_null (opt.method);
|
||||
|
||||
#endif /* DEBUG_MALLOC */
|
||||
}
|
||||
@@ -1761,34 +1798,27 @@ cleanup (void)
|
||||
#ifdef TESTING
|
||||
|
||||
const char *
|
||||
test_commands_sorted()
|
||||
test_commands_sorted(void)
|
||||
{
|
||||
int prev_idx = 0, next_idx = 1;
|
||||
int command_count = countof (commands) - 1;
|
||||
int cmp = 0;
|
||||
while (next_idx <= command_count)
|
||||
unsigned i;
|
||||
|
||||
for (i = 1; i < countof(commands); ++i)
|
||||
{
|
||||
cmp = strcasecmp (commands[prev_idx].name, commands[next_idx].name);
|
||||
if (cmp > 0)
|
||||
if (strcasecmp (commands[i - 1].name, commands[i].name) > 0)
|
||||
{
|
||||
mu_assert ("FAILED", false);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_idx ++;
|
||||
next_idx ++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
test_cmd_spec_restrict_file_names()
|
||||
test_cmd_spec_restrict_file_names(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *val;
|
||||
unsigned i;
|
||||
static const struct {
|
||||
const char *val;
|
||||
int expected_restrict_files_os;
|
||||
int expected_restrict_files_ctrl;
|
||||
int expected_restrict_files_case;
|
||||
@@ -1800,7 +1830,7 @@ test_cmd_spec_restrict_file_names()
|
||||
{ "unix,nocontrol,lowercase,", restrict_unix, false, restrict_lowercase, true },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
bool res;
|
||||
|
||||
@@ -1824,4 +1854,3 @@ test_cmd_spec_restrict_file_names()
|
||||
}
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
|
||||
17
src/iri.c
17
src/iri.c
@@ -129,7 +129,7 @@ locale_to_utf8 (const char *str)
|
||||
return str;
|
||||
|
||||
l2u = iconv_open ("UTF-8", opt.locale);
|
||||
if (l2u != (iconv_t)(-1))
|
||||
if (l2u == (iconv_t)(-1))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Conversion from %s to %s isn't supported\n"),
|
||||
quote (opt.locale), quote ("UTF-8"));
|
||||
@@ -256,22 +256,22 @@ idn_decode (char *host)
|
||||
/* Try to transcode string str from remote encoding to UTF-8. On success, *new
|
||||
contains the transcoded string. *new content is unspecified otherwise. */
|
||||
bool
|
||||
remote_to_utf8 (struct iri *i, const char *str, const char **new)
|
||||
remote_to_utf8 (struct iri *iri, const char *str, const char **new)
|
||||
{
|
||||
iconv_t cd;
|
||||
bool ret = false;
|
||||
|
||||
if (!i->uri_encoding)
|
||||
if (!iri->uri_encoding)
|
||||
return false;
|
||||
|
||||
/* When `i->uri_encoding' == "UTF-8" there is nothing to convert. But we must
|
||||
test for non-ASCII symbols for correct hostname processing in `idn_encode'
|
||||
function. */
|
||||
if (!strcmp (i->uri_encoding, "UTF-8"))
|
||||
if (!strcmp (iri->uri_encoding, "UTF-8"))
|
||||
{
|
||||
int i, len = strlen (str);
|
||||
for (i = 0; i < len; i++)
|
||||
if ((unsigned char) str[i] >= (unsigned char) '\200')
|
||||
const char *p = str;
|
||||
for (p = str; *p; p++)
|
||||
if (*p < 0)
|
||||
{
|
||||
*new = strdup (str);
|
||||
return true;
|
||||
@@ -279,7 +279,7 @@ remote_to_utf8 (struct iri *i, const char *str, const char **new)
|
||||
return false;
|
||||
}
|
||||
|
||||
cd = iconv_open ("UTF-8", i->uri_encoding);
|
||||
cd = iconv_open ("UTF-8", iri->uri_encoding);
|
||||
if (cd == (iconv_t)(-1))
|
||||
return false;
|
||||
|
||||
@@ -365,4 +365,3 @@ set_content_encoding (struct iri *i, char *charset)
|
||||
|
||||
i->content_encoding = charset ? xstrdup (charset) : NULL;
|
||||
}
|
||||
|
||||
|
||||
11
src/log.c
11
src/log.c
@@ -39,6 +39,7 @@ as that of the covered work. */
|
||||
#include <errno.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "exits.h"
|
||||
#include "log.h"
|
||||
|
||||
/* 2005-10-25 SMS.
|
||||
@@ -278,6 +279,10 @@ saved_append (const char *s)
|
||||
#define CHECK_VERBOSE(x) \
|
||||
switch (x) \
|
||||
{ \
|
||||
case LOG_PROGRESS: \
|
||||
if (!opt.show_progress) \
|
||||
return; \
|
||||
break; \
|
||||
case LOG_ALWAYS: \
|
||||
break; \
|
||||
case LOG_NOTQUIET: \
|
||||
@@ -543,7 +548,7 @@ logprintf (enum log_options o, const char *fmt, ...)
|
||||
va_end (args);
|
||||
|
||||
if (done && errno == EPIPE)
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
while (!done);
|
||||
}
|
||||
@@ -587,7 +592,7 @@ log_init (const char *file, bool appendp)
|
||||
if (!logfp)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -871,7 +876,7 @@ redirect_output (void)
|
||||
can do but disable printing completely. */
|
||||
fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
|
||||
fprintf (stderr, _("%s: %s; disabling logging.\n"),
|
||||
logfile, strerror (errno));
|
||||
(logfile) ? logfile : DEFAULT_LOGFILE, strerror (errno));
|
||||
inhibit_logging = true;
|
||||
}
|
||||
save_context_p = false;
|
||||
|
||||
@@ -36,7 +36,7 @@ as that of the covered work. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
enum log_options { LOG_VERBOSE, LOG_NOTQUIET, LOG_NONVERBOSE, LOG_ALWAYS };
|
||||
enum log_options { LOG_VERBOSE, LOG_NOTQUIET, LOG_NONVERBOSE, LOG_ALWAYS, LOG_PROGRESS };
|
||||
|
||||
void log_set_warc_log_fp (FILE *);
|
||||
|
||||
|
||||
744
src/main.c
744
src/main.c
File diff suppressed because it is too large
Load Diff
470
src/metalink.c
Normal file
470
src/metalink.c
Normal file
@@ -0,0 +1,470 @@
|
||||
/* Declarations for HTTP.
|
||||
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this program, or any covered work, by linking or
|
||||
combining it with the OpenSSL project's OpenSSL library (or a
|
||||
modified version of that library), containing parts covered by the
|
||||
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
grants you additional permission to convey the resulting work.
|
||||
Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <metalink/metalink_parser.h>
|
||||
#include <metalink/metalink_types.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "md5.h"
|
||||
#include "sha1.h"
|
||||
#include "sha256.h"
|
||||
#include "metalink.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
#define HASH_TYPES 3
|
||||
/* Between MD5, SHA1 and SHA256, SHA256 has the greatest hash length, which is
|
||||
32. In the line below, 64 is written to have a more readable code. */
|
||||
#define MAX_DIGEST_LENGTH 32
|
||||
|
||||
static char supported_hashes[HASH_TYPES][7] = {"sha256", "sha1", "md5"};
|
||||
static int digest_sizes[HASH_TYPES] = {SHA256_DIGEST_SIZE, SHA1_DIGEST_SIZE, MD5_DIGEST_SIZE};
|
||||
static int (*hash_function[HASH_TYPES]) (FILE *, void *) = {sha256_stream, sha1_stream, md5_stream};
|
||||
|
||||
/* First, parse the metalink using libmetalink functions and structures. Then
|
||||
pass the information to an internal set of structures. */
|
||||
mlink *
|
||||
parse_metalink(char *input_file)
|
||||
{
|
||||
int err;
|
||||
metalink_t *metalink;
|
||||
metalink_file_t **files;
|
||||
metalink_resource_t **resources;
|
||||
metalink_checksum_t **checksums;
|
||||
metalink_chunk_checksum_t *chunk_checksum;
|
||||
metalink_piece_hash_t **piece_hashes;
|
||||
mlink *m_link;
|
||||
err = metalink_parse_file (input_file, &metalink);
|
||||
if(err != 0 || !metalink)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Libmetalink could not parse the metalink file.\n");
|
||||
return NULL;
|
||||
}
|
||||
else if(metalink->files == NULL) {
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Metalink doesn't have any file data.\n");
|
||||
metalink_delete(metalink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_link = malloc (sizeof *m_link);
|
||||
m_link->identity = (metalink->identity ? xstrdup (metalink->identity) : NULL);
|
||||
m_link->tags = (metalink->tags ? xstrdup (metalink->tags) : NULL);
|
||||
m_link->files = NULL;
|
||||
m_link->num_of_files = 0;
|
||||
|
||||
for (files = metalink->files; *files; ++files)
|
||||
{
|
||||
mlink_file *file;
|
||||
|
||||
if (!(*files)->name)
|
||||
{
|
||||
/* File name is missing */
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping file"
|
||||
" due to missing name/path.\n");
|
||||
continue;
|
||||
}
|
||||
else if (!(*files)->resources)
|
||||
{
|
||||
/* URL is missing */
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping file(%s)"
|
||||
" due to missing resources.\n", (*files)->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
file = malloc(sizeof(mlink_file));
|
||||
++(m_link->num_of_files);
|
||||
file -> next = (m_link->files);
|
||||
(m_link->files) = file;
|
||||
|
||||
file->name = xstrdup ((*files)->name);
|
||||
file->size = (*files)->size;
|
||||
file->maxconnections = (*files)->maxconnections;
|
||||
file->version = ((*files)->version ? xstrdup ((*files)->version) : NULL);
|
||||
file->language = ((*files)->language ? xstrdup ((*files)->language) : NULL);
|
||||
file->os = ((*files)->os ? xstrdup ((*files)->os) : NULL);
|
||||
file->resources = NULL;
|
||||
file->checksums = NULL;
|
||||
file->chunk_checksum = NULL;
|
||||
file->num_of_res = file->num_of_checksums = 0;
|
||||
|
||||
for (resources = (*files)->resources; *resources; ++resources)
|
||||
{
|
||||
mlink_resource *resource;
|
||||
|
||||
if (!(*resources)->url)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping resource"
|
||||
" due to missing URL.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
resource = malloc (sizeof(mlink_resource));
|
||||
++(file->num_of_res);
|
||||
|
||||
resource->url = xstrdup ((*resources)->url);
|
||||
resource->type = ((*resources)->type ? xstrdup ((*resources)->type) : NULL);
|
||||
resource->location = ((*resources)->location ? xstrdup ((*resources)->location) : NULL);
|
||||
resource->preference = (*resources)->preference;
|
||||
resource->maxconnections = (*resources)->maxconnections;
|
||||
|
||||
resource->next = (file->resources);
|
||||
(file->resources) = resource;
|
||||
}
|
||||
|
||||
for (checksums = (*files)->checksums; *checksums; ++checksums)
|
||||
{
|
||||
mlink_checksum *checksum = malloc (sizeof(mlink_checksum));
|
||||
|
||||
if (!(*checksums)->type)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping checksum"
|
||||
" due to missing hash type.\n");
|
||||
continue;
|
||||
}
|
||||
else if (!(*checksums)->hash)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping resource"
|
||||
" due to missing hash value.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
checksum->type = ((*checksums)->type ? xstrdup ((*checksums)->type) : NULL);
|
||||
checksum->hash = ((*checksums)->hash ? xstrdup ((*checksums)->hash) : NULL);
|
||||
|
||||
checksum->next = (file->checksums);
|
||||
(file->checksums) = checksum;
|
||||
}
|
||||
|
||||
if((chunk_checksum = (*files)->chunk_checksum))
|
||||
{
|
||||
mlink_chunk_checksum *chunk_sum;
|
||||
|
||||
if(!chunk_checksum->type)
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping chunk checksum"
|
||||
" due to missing type information.\n");
|
||||
else
|
||||
{
|
||||
chunk_sum = malloc (sizeof(mlink_chunk_checksum));
|
||||
chunk_sum->length = chunk_checksum->length;
|
||||
chunk_sum->type = (chunk_checksum->type ? xstrdup (chunk_checksum->type) : NULL);
|
||||
for (piece_hashes = chunk_checksum->piece_hashes; *piece_hashes; ++piece_hashes)
|
||||
{
|
||||
mlink_piece_hash piece_hash;
|
||||
if(!chunk_checksum->type)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "PARSE METALINK: Skipping chunk checksum"
|
||||
" due to missing hash value for piece(%d).\n",
|
||||
(*piece_hashes)->piece);
|
||||
free (chunk_sum);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metalink_delete(metalink);
|
||||
return m_link;
|
||||
}
|
||||
|
||||
/* Elect resouces so that only the URLs with type HTTP and FTP (i.e. the
|
||||
protocols supported by Metalink&GNU Wget) remain on the list of resources. */
|
||||
void
|
||||
elect_resources (mlink *mlink)
|
||||
{
|
||||
mlink_file *file;
|
||||
mlink_resource *res, *res_next;
|
||||
|
||||
for (file = mlink->files; file; file = file->next)
|
||||
{
|
||||
res = file->resources;
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
while (res_next = res->next)
|
||||
{
|
||||
if (strcmp(res_next->type, "ftp") && strcmp(res_next->type, "http"))
|
||||
{
|
||||
res->next = res_next->next;
|
||||
free(res_next);
|
||||
}
|
||||
else
|
||||
res = res_next;
|
||||
}
|
||||
res = file->resources;
|
||||
if (strcmp(res->type, "ftp") && strcmp(res->type, "http"))
|
||||
{
|
||||
file->resources = res->next;
|
||||
free(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Elect checksums so that only the hashes with types MD5, SHA-1 or SHA-256
|
||||
(i.e. the hashes supported by Metalink) remain on the list of checksums. */
|
||||
void
|
||||
elect_checksums (mlink *mlink)
|
||||
{
|
||||
int i;
|
||||
mlink_file *file = mlink -> files;
|
||||
mlink_checksum *csum, *csum_next;
|
||||
|
||||
for (; file; file = file->next)
|
||||
{
|
||||
csum = file->checksums;
|
||||
if (!csum)
|
||||
continue;
|
||||
|
||||
while (csum_next = csum->next)
|
||||
{
|
||||
/* Traverse supported hash types & break if csum->type is the same. */
|
||||
for (i = 0; i < HASH_TYPES; ++i)
|
||||
if (!strcmp(csum_next->type, supported_hashes[i]))
|
||||
break;
|
||||
|
||||
if(i == HASH_TYPES)
|
||||
{
|
||||
csum->next = csum_next->next;
|
||||
free(csum_next);
|
||||
}
|
||||
else
|
||||
csum=csum_next;
|
||||
}
|
||||
csum = file->checksums;
|
||||
for (i = 0; i < HASH_TYPES; ++i)
|
||||
if (!strcmp(csum->type, supported_hashes[i]))
|
||||
break;
|
||||
if(i == HASH_TYPES)
|
||||
{
|
||||
file->checksums = csum->next;
|
||||
free(csum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the space allocated for the whole mlink structure. */
|
||||
void
|
||||
delete_mlink(mlink *metalink)
|
||||
{
|
||||
mlink_file *file, *file_temp;
|
||||
mlink_resource *res, *res_temp;
|
||||
mlink_checksum *csum, *csum_temp;
|
||||
mlink_piece_hash *phash, *phash_temp;
|
||||
|
||||
if(!metalink)
|
||||
return;
|
||||
|
||||
xfree_null (metalink->tags);
|
||||
xfree_null (metalink->identity);
|
||||
|
||||
file = metalink->files;
|
||||
while (file)
|
||||
{
|
||||
xfree_null(file->os);
|
||||
xfree_null(file->language);
|
||||
xfree_null(file->version);
|
||||
xfree_null(file->name);
|
||||
|
||||
res = file->resources;
|
||||
while (res)
|
||||
{
|
||||
xfree_null (res->url);
|
||||
xfree_null (res->type);
|
||||
xfree_null (res->location);
|
||||
|
||||
res_temp = res;
|
||||
res = res->next;
|
||||
free (res_temp);
|
||||
}
|
||||
|
||||
csum = file->checksums;
|
||||
while (csum)
|
||||
{
|
||||
xfree_null (csum->type);
|
||||
xfree_null (csum->hash);
|
||||
|
||||
csum_temp = csum;
|
||||
csum = csum->next;
|
||||
free (csum_temp);
|
||||
}
|
||||
|
||||
if(file->chunk_checksum)
|
||||
{
|
||||
free (file->chunk_checksum->type);
|
||||
phash = file->chunk_checksum->piece_hashes;
|
||||
while (phash)
|
||||
{
|
||||
xfree_null (phash->hash);
|
||||
|
||||
phash_temp = phash;
|
||||
phash = phash->next;
|
||||
free (phash_temp);
|
||||
}
|
||||
}
|
||||
|
||||
file_temp = file;
|
||||
file = file->next;
|
||||
free (file_temp);
|
||||
}
|
||||
free (metalink);
|
||||
}
|
||||
|
||||
/* Parses metalink into type metalink_t and returns a pointer to it.
|
||||
Returns NULL if the parsing is failed. */
|
||||
metalink_t*
|
||||
metalink_context (const char *url)
|
||||
{
|
||||
metalink_error_t err;
|
||||
metalink_t* metalink;
|
||||
|
||||
err = metalink_parse_file (url, &metalink);
|
||||
|
||||
if(err != 0)
|
||||
metalink = NULL;
|
||||
return metalink;
|
||||
}
|
||||
|
||||
/* It should be taken into account that file hashes in metalink files may
|
||||
include uppercase letter. This function turns the case of the first length
|
||||
letters in the space pointed by hash into lowercase. */
|
||||
static void
|
||||
lower_hex_case (unsigned char *hash, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* 32 is the difference between the ascii codes of 'a' and 'A'. */
|
||||
for(i = 0; i < length; ++i)
|
||||
if('A' <= hash[i] && hash[i] <= 'Z')
|
||||
hash[i] += 32;
|
||||
}
|
||||
|
||||
/* Verifies file hash by comparing the file hashes found by gnulib functions
|
||||
and hashes provided by metalink file. Works by comparing strongest supported
|
||||
hash type available in the metalink file.
|
||||
|
||||
Returns;
|
||||
-1 if hashes that were compared turned out to be different.
|
||||
0 if all pairs of hashes compared turned out to be the same.
|
||||
1 if due to some error, comparisons could not be made. */
|
||||
int
|
||||
verify_file_hash (const char *filename, mlink_checksum *checksums)
|
||||
{
|
||||
int i, j, req_type, res = 0;
|
||||
|
||||
unsigned char hash_raw[MAX_DIGEST_LENGTH];
|
||||
/* Points to a hash of supported type from the metalink file. The index dedicated
|
||||
to a type is inversely proportional to its strength. (check supported_types
|
||||
to see the supported hash types listed in decreasing order of strength)*/
|
||||
unsigned char *metalink_hashes[HASH_TYPES];
|
||||
unsigned char file_hash[2 * MAX_DIGEST_LENGTH + 1];
|
||||
FILE *file;
|
||||
mlink_checksum *checksum;
|
||||
|
||||
if (!checksums)
|
||||
{
|
||||
/* Metalink file has no hashes for this file. */
|
||||
logprintf (LOG_VERBOSE, "Validating(%s) failed: digest missing in metalink file.\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < HASH_TYPES; ++i)
|
||||
metalink_hashes[i] = NULL;
|
||||
|
||||
/* Fill metalink_hashes to contain an instance of supported types of hashes. */
|
||||
for (checksum = checksums; checksum; checksum = checksum->next)
|
||||
for (j = 0; j < HASH_TYPES; ++j)
|
||||
if (!strcmp(checksum->type, supported_hashes[j]))
|
||||
{
|
||||
if(metalink_hashes[j])
|
||||
{
|
||||
/* As of libmetalin-0.03, it is not checked during parsing the
|
||||
information in the metalink file whether there are multiple
|
||||
hashes of same type for one file. That case should be checked,
|
||||
as none of those hashes can be trusted above the other. */
|
||||
logprintf (LOG_VERBOSE, "Validating(%s) failed: metalink file contains different hashes of same type.\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
metalink_hashes[j] = checksum->hash;
|
||||
}
|
||||
|
||||
for (i = 0; !metalink_hashes[i]; ++i);
|
||||
|
||||
if (i == HASH_TYPES)
|
||||
{
|
||||
/* no hash of supported types could be found. */
|
||||
logprintf (LOG_VERBOSE, "Validating(%s) failed: No hash of supported types could be found in metalink file.\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
req_type = i;
|
||||
|
||||
if (!(file = fopen(filename, "rb")))
|
||||
{
|
||||
/* File could not be opened. */
|
||||
logprintf (LOG_VERBOSE, "Validating(%s) failed: file could not be opened.\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = (*hash_function[req_type]) (file, hash_raw);
|
||||
fclose(file);
|
||||
|
||||
/* Find file hash accordingly. */
|
||||
if (res)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Validating(%s) failed: File hash could not be found.\n",
|
||||
filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Turn byte-form hash to hex form. */
|
||||
for(j = 0 ; j < digest_sizes[req_type]; ++j)
|
||||
sprintf(file_hash + 2 * j, "%02x", hash_raw[j]);
|
||||
|
||||
lower_hex_case(metalink_hashes[req_type], 2 * digest_sizes[req_type]);
|
||||
if (strcmp(metalink_hashes[req_type], file_hash))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Verifying(%s) failed: %s hashes are different.\n",
|
||||
filename, supported_hashes[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
logprintf (LOG_VERBOSE, "Verifying(%s): %s hashes are the same.\n",
|
||||
filename, supported_hashes[i]);
|
||||
return 0;
|
||||
}
|
||||
106
src/metalink.h
Normal file
106
src/metalink.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Declarations for metalink.c.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this program, or any covered work, by linking or
|
||||
combining it with the OpenSSL project's OpenSSL library (or a
|
||||
modified version of that library), containing parts covered by the
|
||||
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
grants you additional permission to convey the resulting work.
|
||||
Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#ifndef MLINK_H
|
||||
#define MLINK_H
|
||||
|
||||
typedef struct metalink_piece_hash
|
||||
{
|
||||
struct metalink_piece_hash *next;
|
||||
|
||||
int piece;
|
||||
char *hash;
|
||||
} mlink_piece_hash;
|
||||
|
||||
typedef struct metalink_checksum
|
||||
{
|
||||
struct metalink_checksum *next;
|
||||
|
||||
char *type;
|
||||
char *hash;
|
||||
} mlink_checksum;
|
||||
|
||||
typedef struct metalink_resource
|
||||
{
|
||||
struct metalink_resource *next;
|
||||
|
||||
char *url;
|
||||
char *type;
|
||||
char *location;
|
||||
int preference;
|
||||
int maxconnections;
|
||||
} mlink_resource;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *type;
|
||||
int length;
|
||||
mlink_piece_hash *piece_hashes;
|
||||
} mlink_chunk_checksum;
|
||||
|
||||
typedef struct metalink_file
|
||||
{
|
||||
struct metalink_file *next;
|
||||
|
||||
char *name;
|
||||
long long int size;
|
||||
char *version;
|
||||
char *language;
|
||||
char *os;
|
||||
int maxconnections;
|
||||
mlink_resource *resources;
|
||||
int num_of_res;
|
||||
mlink_checksum *checksums;
|
||||
int num_of_checksums;
|
||||
mlink_chunk_checksum *chunk_checksum;
|
||||
} mlink_file;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *identity;
|
||||
char *tags;
|
||||
mlink_file *files;
|
||||
int num_of_files;
|
||||
} mlink;
|
||||
|
||||
mlink *parse_metalink (char *);
|
||||
|
||||
void elect_resources (mlink *);
|
||||
|
||||
void elect_checksums (mlink *);
|
||||
|
||||
void delete_mlink (mlink *);
|
||||
|
||||
metalink_t *metalink_context (const char *);
|
||||
|
||||
int verify_file_hash (const char *, mlink_checksum *);
|
||||
|
||||
#endif /* MLINK_H */
|
||||
@@ -1,6 +1,6 @@
|
||||
/* mswindows.c -- Windows-specific support
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -42,6 +42,7 @@ as that of the covered work. */
|
||||
|
||||
#include "utils.h"
|
||||
#include "url.h"
|
||||
#include "exits.h"
|
||||
|
||||
#ifndef ES_SYSTEM_REQUIRED
|
||||
#define ES_SYSTEM_REQUIRED 0x00000001
|
||||
@@ -164,8 +165,8 @@ fake_fork_child (void)
|
||||
if (new_log_fp)
|
||||
{
|
||||
info->logfile_changed = true;
|
||||
strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
|
||||
info->lfilename[sizeof (info->lfilename) - 1] = '\0';
|
||||
snprintf (info->lfilename, sizeof (info->lfilename), "%s",
|
||||
opt.lfilename);
|
||||
fclose (new_log_fp);
|
||||
}
|
||||
}
|
||||
@@ -308,7 +309,7 @@ cleanup:
|
||||
|
||||
/* We're the parent. If all is well, terminate. */
|
||||
if (rv)
|
||||
exit (0);
|
||||
exit (WGET_EXIT_SUCCESS);
|
||||
|
||||
/* We failed, return. */
|
||||
}
|
||||
@@ -323,7 +324,7 @@ fork_to_background (void)
|
||||
rv = fake_fork_child ();
|
||||
if (rv < 0)
|
||||
{
|
||||
fprintf (stderr, "fake_fork_child() failed\n");
|
||||
fprintf (stderr, _("fake_fork_child() failed\n"));
|
||||
abort ();
|
||||
}
|
||||
else if (rv == 0)
|
||||
@@ -331,7 +332,7 @@ fork_to_background (void)
|
||||
/* We're the parent. */
|
||||
fake_fork ();
|
||||
/* If fake_fork() returns, it failed. */
|
||||
fprintf (stderr, "fake_fork() failed\n");
|
||||
fprintf (stderr, _("fake_fork() failed\n"));
|
||||
abort ();
|
||||
}
|
||||
/* If we get here, we're the child. */
|
||||
@@ -461,7 +462,7 @@ ws_startup (void)
|
||||
{
|
||||
fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
|
||||
exec_name);
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
if (data.wVersion < requested)
|
||||
@@ -469,7 +470,7 @@ ws_startup (void)
|
||||
fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
|
||||
exec_name);
|
||||
WSACleanup ();
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
atexit (ws_cleanup);
|
||||
@@ -620,35 +621,35 @@ inet_ntop (int af, const void *src, char *dst, socklen_t cnt)
|
||||
void
|
||||
set_windows_fd_as_blocking_socket (int fd)
|
||||
{
|
||||
/* 04/2011
|
||||
/* 04/2011
|
||||
gnulib select() converts blocking sockets to nonblocking in windows
|
||||
discussed here:
|
||||
http://old.nabble.com/blocking-socket-is-nonblocking-after-calling-gnulib-
|
||||
select%28%29-in-windows-td31432857.html
|
||||
|
||||
wget uses blocking sockets so we must convert them back to blocking.
|
||||
*/
|
||||
int ret = 0;
|
||||
int wsagle = 0;
|
||||
const int zero = 0;
|
||||
*/
|
||||
int ret = 0;
|
||||
int wsagle = 0;
|
||||
const int zero = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if(wsagle == WSAEINPROGRESS)
|
||||
Sleep(1); /* use windows sleep */
|
||||
|
||||
WSASetLastError (0);
|
||||
ret = ioctl (fd, FIONBIO, &zero);
|
||||
wsagle = WSAGetLastError();
|
||||
}
|
||||
do
|
||||
{
|
||||
if(wsagle == WSAEINPROGRESS)
|
||||
Sleep(1); /* use windows sleep */
|
||||
|
||||
WSASetLastError (0);
|
||||
ret = ioctl (fd, FIONBIO, &zero);
|
||||
wsagle = WSAGetLastError ();
|
||||
}
|
||||
while (ret && (wsagle == WSAEINPROGRESS));
|
||||
|
||||
if(ret)
|
||||
if(ret)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"ioctl() failed. The socket could not be set as blocking.\n" );
|
||||
_("ioctl() failed. The socket could not be set as blocking.\n") );
|
||||
DEBUGP (("Winsock error: %d\n", WSAGetLastError ()));
|
||||
abort ();
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,13 +57,6 @@ as that of the covered work. */
|
||||
/* Declares getpid(). */
|
||||
#include <process.h>
|
||||
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(m) (((m) & (_S_IFMT)) == (_S_IFDIR))
|
||||
#endif
|
||||
#ifndef S_ISLNK
|
||||
# define S_ISLNK(a) 0
|
||||
#endif
|
||||
|
||||
/* We have strcasecmp and strncasecmp, just under different names. */
|
||||
#ifndef HAVE_STRCASECMP
|
||||
# define strcasecmp stricmp
|
||||
@@ -90,18 +83,6 @@ typedef __int64 wgint;
|
||||
# define strtoll_type __int64
|
||||
#endif
|
||||
|
||||
/* Windows has no symlink, therefore no lstat. Without symlinks lstat
|
||||
is equivalent to stat anyway. */
|
||||
#define lstat stat
|
||||
|
||||
/* Define LFS aliases for stat and fstat. */
|
||||
#ifdef stat_alias
|
||||
# define stat(f, b) stat_alias (f, b)
|
||||
#endif
|
||||
#ifdef fstat_alias
|
||||
# define fstat(f, b) fstat_alias (f, b)
|
||||
#endif
|
||||
|
||||
#define PATH_SEPARATOR '\\'
|
||||
|
||||
/* Additional declarations needed for IPv6: */
|
||||
|
||||
239
src/multi.c
Normal file
239
src/multi.c
Normal file
@@ -0,0 +1,239 @@
|
||||
/* Declarations for HTTP.
|
||||
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this program, or any covered work, by linking or
|
||||
combining it with the OpenSSL project's OpenSSL library (or a
|
||||
modified version of that library), containing parts covered by the
|
||||
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
grants you additional permission to convey the resulting work.
|
||||
Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "multi.h"
|
||||
#include "url.h"
|
||||
#include "exits.h"
|
||||
|
||||
static struct range *ranges;
|
||||
char **files;
|
||||
|
||||
/* Allocate space for temporary file names. */
|
||||
void
|
||||
init_temp_files()
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!(files = malloc (opt.jobs * (sizeof *files))))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Space for temporary file data could not be allocated.\n");
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
for (i = 0; i < opt.jobs; ++i)
|
||||
if(!(files[i] = malloc (L_tmpnam * sizeof(char))))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Space for temporary file names could not be allocated.\n");
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign names to temporary files to be used. */
|
||||
void
|
||||
name_temp_files()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < opt.jobs; ++i)
|
||||
if(!tmpnam(files[i]))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Temporary file name could not be assigned.\n");
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge the temporary files in which the chunks are stored to form the
|
||||
resulting file(output). */
|
||||
void
|
||||
merge_temp_files(char *output)
|
||||
{
|
||||
FILE *out, *in;
|
||||
int j, ret;
|
||||
void *buf = malloc (MIN_CHUNK_SIZE);
|
||||
|
||||
out = fopen (output, "wb");
|
||||
for(j = 0; j < opt.jobs; ++j)
|
||||
{
|
||||
in = fopen(files[j],"rb");
|
||||
ret = MIN_CHUNK_SIZE;
|
||||
while(ret == MIN_CHUNK_SIZE)
|
||||
{
|
||||
ret = fread(buf, 1, MIN_CHUNK_SIZE, in);
|
||||
fwrite(buf, 1, ret, out);
|
||||
}
|
||||
fclose(in);
|
||||
}
|
||||
fclose(out);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Delete the temporary files used. */
|
||||
void
|
||||
delete_temp_files()
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
while(j < opt.jobs)
|
||||
unlink(files[j++]);
|
||||
}
|
||||
|
||||
/* Clean the space allocated for temporary files data. */
|
||||
void
|
||||
clean_temp_files()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < opt.jobs; ++i)
|
||||
free (files[i]);
|
||||
free(files);
|
||||
}
|
||||
|
||||
/* Allocate ranges array to store the ranges data. */
|
||||
void
|
||||
init_ranges()
|
||||
{
|
||||
if(!(ranges = malloc (opt.jobs * (sizeof *ranges))))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Space for ranges data could not be allocated.\n");
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign values to the ranges.
|
||||
Also allocates the resources array each struct range must have.
|
||||
|
||||
Returns the number of ranges to which values are assigned. */
|
||||
int
|
||||
fill_ranges_data(int num_of_resources, long long int file_size,
|
||||
long int chunk_size)
|
||||
{
|
||||
int i, r;
|
||||
i = 0;
|
||||
do
|
||||
{
|
||||
ranges[i].first_byte = i * chunk_size;
|
||||
ranges[i].last_byte = (i+1) * chunk_size - 1;
|
||||
ranges[i].bytes_covered = ranges[i].is_assigned = 0;
|
||||
ranges[i].resources = malloc(num_of_resources * sizeof(bool));
|
||||
ranges[i].status_least_severe = RETROK;
|
||||
for (r = 0; r < num_of_resources; ++r)
|
||||
ranges[i].resources[r] = false;
|
||||
++i;
|
||||
} while (ranges[i-1].last_byte < (file_size - 1));
|
||||
ranges[i-1].last_byte = file_size -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Free the resources array of each range allocated by fill_ranges_data(). */
|
||||
void
|
||||
clean_range_res_data()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < opt.jobs; ++i)
|
||||
free (ranges[i].resources);
|
||||
}
|
||||
|
||||
/* Free the ranges array that is used for storing ranges' data. */
|
||||
void
|
||||
clean_ranges()
|
||||
{
|
||||
free (ranges);
|
||||
ranges = NULL;
|
||||
}
|
||||
|
||||
/* Assign 'last minute' data to struct s_thread_ctx instances regarding their
|
||||
usage and range information. Then create a thread using that instance. */
|
||||
int
|
||||
spawn_thread (struct s_thread_ctx *thread_ctx, int index, int resource)
|
||||
{
|
||||
static pthread_t thread;
|
||||
|
||||
thread_ctx[index].url_parsed = url_parse (thread_ctx[index].url,
|
||||
&(thread_ctx[index].url_err), thread_ctx[index].i, true);
|
||||
if(!thread_ctx[index].url_parsed)
|
||||
return 1;
|
||||
|
||||
thread_ctx[index].file = files[index];
|
||||
thread_ctx[index].range = ranges + index;
|
||||
(thread_ctx[index].range)->is_assigned = 1;
|
||||
(thread_ctx[index].range)->resources[resource] = true;
|
||||
|
||||
thread_ctx[index].used = 1;
|
||||
thread_ctx[index].terminated = 0;
|
||||
|
||||
return pthread_create (&thread, NULL, segmented_retrieve_url, &thread_ctx[index]);
|
||||
}
|
||||
|
||||
/* Collects the first thread to terminate and updates struct s_thread_ctx
|
||||
instance's data regarding its 'business' (i.e. being used by a thread).
|
||||
|
||||
Returns the index of the struct s_thread_ctx instance that was used in the
|
||||
terminating thread. */
|
||||
int
|
||||
collect_thread (sem_t *retr_sem, struct s_thread_ctx *thread_ctx)
|
||||
{
|
||||
int k, ret;
|
||||
do
|
||||
ret = sem_wait (retr_sem);
|
||||
while (ret < 0 && errno == EINTR);
|
||||
|
||||
for (k = 0; k < opt.jobs; k++)
|
||||
if (thread_ctx[k].used && thread_ctx[k].terminated)
|
||||
{
|
||||
url_free (thread_ctx[k].url_parsed);
|
||||
thread_ctx[k].used = 0;
|
||||
(thread_ctx[k].range)->is_assigned = 0;
|
||||
return k;
|
||||
}
|
||||
}
|
||||
|
||||
/* The function which is being called by pthread_create in spawn_thread(). It
|
||||
is used to call retrieve_url(), which requires many arguments. */
|
||||
static void *
|
||||
segmented_retrieve_url (void *arg)
|
||||
{
|
||||
struct s_thread_ctx *ctx = (struct s_thread_ctx *) arg;
|
||||
|
||||
ctx->status = retrieve_url (ctx->url_parsed, ctx->url,
|
||||
&ctx->file, &ctx->redirected,
|
||||
ctx->referer, &ctx->dt,
|
||||
false, ctx->i, true, ctx->range);
|
||||
ctx->terminated = 1;
|
||||
sem_post (ctx->retr_sem);
|
||||
}
|
||||
89
src/multi.h
Normal file
89
src/multi.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* Declarations for HTTP.
|
||||
Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this program, or any covered work, by linking or
|
||||
combining it with the OpenSSL project's OpenSSL library (or a
|
||||
modified version of that library), containing parts covered by the
|
||||
terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
grants you additional permission to convey the resulting work.
|
||||
Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#ifndef MULTI_H
|
||||
#define MULTI_H
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include "iri.h"
|
||||
#include "url.h"
|
||||
|
||||
#define MIN_CHUNK_SIZE 2048
|
||||
|
||||
struct s_thread_ctx
|
||||
{
|
||||
pthread_t thread;
|
||||
int used;
|
||||
int terminated;
|
||||
int dt, url_err;
|
||||
char *redirected;
|
||||
char *referer;
|
||||
struct url *url_parsed;
|
||||
struct iri *i;
|
||||
struct range *range;
|
||||
char *file;
|
||||
char *url;
|
||||
#ifdef ENABLE_THREADS
|
||||
sem_t *retr_sem;
|
||||
#else
|
||||
/* Not used. */
|
||||
void *retr_sem;
|
||||
#endif
|
||||
uerr_t status;
|
||||
};
|
||||
|
||||
void init_temp_files();
|
||||
|
||||
void name_temp_files();
|
||||
|
||||
void merge_temp_files(char *);
|
||||
|
||||
void delete_temp_files();
|
||||
|
||||
void clean_temp_files();
|
||||
|
||||
void init_ranges();
|
||||
|
||||
int fill_ranges_data(int, long long int, long int);
|
||||
|
||||
void clean_range_res_data();
|
||||
|
||||
void clean_ranges();
|
||||
|
||||
int spawn_thread (struct s_thread_ctx*, int, int);
|
||||
|
||||
int collect_thread (sem_t *, struct s_thread_ctx *);
|
||||
|
||||
static void * segmented_retrieve_url (void *);
|
||||
|
||||
#endif /* MULTI_H */
|
||||
78
src/netrc.c
78
src/netrc.c
@@ -44,10 +44,16 @@ as that of the covered work. */
|
||||
|
||||
#define NETRC_FILE_NAME ".netrc"
|
||||
|
||||
acc_t *netrc_list;
|
||||
static acc_t *netrc_list;
|
||||
|
||||
static acc_t *parse_netrc (const char *);
|
||||
|
||||
void
|
||||
netrc_cleanup(void)
|
||||
{
|
||||
free_netrc (netrc_list);
|
||||
}
|
||||
|
||||
/* Return the correct user and password, given the host, user (as
|
||||
given in the URL), and password (as given in the URL). May return
|
||||
NULL.
|
||||
@@ -155,8 +161,6 @@ search_netrc (const char *host, const char **acc, const char **passwd,
|
||||
|
||||
#ifdef STANDALONE
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Normally, these functions would be defined by your package. */
|
||||
# define xmalloc malloc
|
||||
# define xfree free
|
||||
@@ -164,48 +168,6 @@ search_netrc (const char *host, const char **acc, const char **passwd,
|
||||
|
||||
# define xrealloc realloc
|
||||
|
||||
/* Read a line from FP. The function reallocs the storage as needed
|
||||
to accomodate for any length of the line. Reallocs are done
|
||||
storage exponentially, doubling the storage after each overflow to
|
||||
minimize the number of calls to realloc() and fgets(). The newline
|
||||
character at the end of line is retained.
|
||||
|
||||
After end-of-file is encountered without anything being read, NULL
|
||||
is returned. NULL is also returned on error. To distinguish
|
||||
between these two cases, use the stdio function ferror(). */
|
||||
|
||||
char *
|
||||
read_whole_line (FILE *fp)
|
||||
{
|
||||
int length = 0;
|
||||
int bufsize = 81;
|
||||
char *line = xmalloc (bufsize);
|
||||
|
||||
while (fgets (line + length, bufsize - length, fp))
|
||||
{
|
||||
length += strlen (line + length);
|
||||
assert (length > 0);
|
||||
if (line[length - 1] == '\n')
|
||||
break;
|
||||
/* fgets() guarantees to read the whole line, or to use up the
|
||||
space we've given it. We can double the buffer
|
||||
unconditionally. */
|
||||
bufsize <<= 1;
|
||||
line = xrealloc (line, bufsize);
|
||||
}
|
||||
if (length == 0 || ferror (fp))
|
||||
{
|
||||
xfree (line);
|
||||
return NULL;
|
||||
}
|
||||
if (length + 1 < bufsize)
|
||||
/* Relieve the memory from our exponential greediness. We say
|
||||
`length + 1' because the terminating \0 is not included in
|
||||
LENGTH. We don't need to zero-terminate the string ourselves,
|
||||
though, because fgets() does that. */
|
||||
line = xrealloc (line, length + 1);
|
||||
return line;
|
||||
}
|
||||
#endif /* STANDALONE */
|
||||
|
||||
/* Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
|
||||
@@ -264,10 +226,11 @@ static acc_t *
|
||||
parse_netrc (const char *path)
|
||||
{
|
||||
FILE *fp;
|
||||
char *line, *p, *tok;
|
||||
char *line = NULL, *p, *tok;
|
||||
const char *premature_token;
|
||||
acc_t *current, *retval;
|
||||
int ln, qmark;
|
||||
size_t bufsize = 0;
|
||||
|
||||
/* The latest token we've seen in the file. */
|
||||
enum
|
||||
@@ -290,7 +253,7 @@ parse_netrc (const char *path)
|
||||
premature_token = NULL;
|
||||
|
||||
/* While there are lines in the file... */
|
||||
while ((line = read_whole_line (fp)) != NULL)
|
||||
while (getline (&line, &bufsize, fp) > 0)
|
||||
{
|
||||
ln ++;
|
||||
|
||||
@@ -423,10 +386,9 @@ parse_netrc (const char *path)
|
||||
exec_name, path, ln, tok);
|
||||
}
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
|
||||
/* Finalize the last machine entry we found. */
|
||||
@@ -484,18 +446,26 @@ main (int argc, char **argv)
|
||||
if (argc < 2 || argc > 3)
|
||||
{
|
||||
fprintf (stderr, _("Usage: %s NETRC [HOSTNAME]\n"), argv[0]);
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
program_name = argv[0];
|
||||
file = argv[1];
|
||||
target = argv[2];
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
/* Set the current locale. */
|
||||
setlocale (LC_ALL, "");
|
||||
/* Set the text message domain. */
|
||||
bindtextdomain ("wget", LOCALEDIR);
|
||||
textdomain ("wget");
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
if (stat (file, &sb))
|
||||
{
|
||||
fprintf (stderr, _("%s: cannot stat %s: %s\n"), argv[0], file,
|
||||
strerror (errno));
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
head = parse_netrc (file);
|
||||
@@ -534,14 +504,14 @@ main (int argc, char **argv)
|
||||
|
||||
/* Exit if we found the target. */
|
||||
if (target)
|
||||
exit (0);
|
||||
exit (WGET_EXIT_SUCCESS);
|
||||
a = a->next;
|
||||
}
|
||||
|
||||
/* Exit with failure if we had a target, success otherwise. */
|
||||
if (target)
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
|
||||
exit (0);
|
||||
exit (WGET_EXIT_SUCCESS);
|
||||
}
|
||||
#endif /* STANDALONE */
|
||||
|
||||
@@ -33,14 +33,15 @@ as that of the covered work. */
|
||||
|
||||
typedef struct _acc_t
|
||||
{
|
||||
char *host; /* NULL if this is the default machine
|
||||
entry. */
|
||||
char *host; /* NULL if this is the default machine
|
||||
entry. */
|
||||
char *acc;
|
||||
char *passwd; /* NULL if there is no password. */
|
||||
char *passwd; /* NULL if there is no password. */
|
||||
struct _acc_t *next;
|
||||
} acc_t;
|
||||
|
||||
void search_netrc (const char *, const char **, const char **, int);
|
||||
void free_netrc (acc_t *l);
|
||||
void netrc_cleanup(void);
|
||||
|
||||
#endif /* NETRC_H */
|
||||
|
||||
104
src/openssl.c
104
src/openssl.c
@@ -153,6 +153,9 @@ key_type_to_ssl_type (enum keyfile_type type)
|
||||
}
|
||||
}
|
||||
|
||||
/* SSL has been initialized */
|
||||
static int ssl_true_initialized = 0;
|
||||
|
||||
/* Create an SSL Context and set default paths etc. Called the first
|
||||
time an HTTP download is attempted.
|
||||
|
||||
@@ -161,6 +164,14 @@ key_type_to_ssl_type (enum keyfile_type type)
|
||||
bool
|
||||
ssl_init (void)
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000
|
||||
if (ssl_true_initialized == 0)
|
||||
{
|
||||
OPENSSL_config (NULL);
|
||||
ssl_true_initialized = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_METHOD const *meth;
|
||||
|
||||
if (ssl_ctx)
|
||||
@@ -194,6 +205,7 @@ ssl_init (void)
|
||||
case secure_protocol_sslv3:
|
||||
meth = SSLv3_client_method ();
|
||||
break;
|
||||
case secure_protocol_pfs:
|
||||
case secure_protocol_tlsv1:
|
||||
meth = TLSv1_client_method ();
|
||||
break;
|
||||
@@ -207,6 +219,12 @@ ssl_init (void)
|
||||
if (!ssl_ctx)
|
||||
goto error;
|
||||
|
||||
/* OpenSSL ciphers: https://www.openssl.org/docs/apps/ciphers.html
|
||||
* Since we want a good protection, we also use HIGH (that excludes MD4 ciphers and some more)
|
||||
*/
|
||||
if (opt.secure_protocol == secure_protocol_pfs)
|
||||
SSL_CTX_set_cipher_list (ssl_ctx, "HIGH:MEDIUM:!RC4:!SRP:!PSK:!RSA:!aNULL@STRENGTH");
|
||||
|
||||
SSL_CTX_set_default_verify_paths (ssl_ctx);
|
||||
SSL_CTX_load_verify_locations (ssl_ctx, opt.ca_cert, opt.ca_directory);
|
||||
|
||||
@@ -251,28 +269,54 @@ ssl_init (void)
|
||||
return false;
|
||||
}
|
||||
|
||||
struct openssl_transport_context {
|
||||
struct openssl_transport_context
|
||||
{
|
||||
SSL *conn; /* SSL connection handle */
|
||||
char *last_error; /* last error printed with openssl_errstr */
|
||||
};
|
||||
|
||||
static int
|
||||
openssl_read (int fd, char *buf, int bufsize, void *arg)
|
||||
struct openssl_read_args
|
||||
{
|
||||
int ret;
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
int fd;
|
||||
struct openssl_transport_context *ctx;
|
||||
char *buf;
|
||||
int bufsize;
|
||||
int retval;
|
||||
};
|
||||
|
||||
static void openssl_read_callback(void *arg)
|
||||
{
|
||||
struct openssl_read_args *args = (struct openssl_read_args *) arg;
|
||||
struct openssl_transport_context *ctx = args->ctx;
|
||||
SSL *conn = ctx->conn;
|
||||
char *buf = args->buf;
|
||||
int bufsize = args->bufsize;
|
||||
int ret;
|
||||
|
||||
do
|
||||
ret = SSL_read (conn, buf, bufsize);
|
||||
while (ret == -1
|
||||
&& SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
|
||||
while (ret == -1 && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
|
||||
&& errno == EINTR);
|
||||
|
||||
return ret;
|
||||
args->retval = ret;
|
||||
}
|
||||
|
||||
static int
|
||||
openssl_write (int fd, char *buf, int bufsize, void *arg)
|
||||
openssl_read (int fd, char *buf, int bufsize, void *arg)
|
||||
{
|
||||
struct openssl_read_args args;
|
||||
args.fd = fd;
|
||||
args.buf = buf;
|
||||
args.bufsize = bufsize;
|
||||
args.ctx = (struct openssl_transport_context*) arg;
|
||||
|
||||
if (run_with_timeout(opt.read_timeout, openssl_read_callback, &args)) {
|
||||
return -1;
|
||||
}
|
||||
return args.retval;
|
||||
}
|
||||
|
||||
static int
|
||||
openssl_write (int fd _GL_UNUSED, char *buf, int bufsize, void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
@@ -314,7 +358,7 @@ openssl_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
}
|
||||
|
||||
static const char *
|
||||
openssl_errstr (int fd, void *arg)
|
||||
openssl_errstr (int fd _GL_UNUSED, void *arg)
|
||||
{
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
unsigned long errcode;
|
||||
@@ -386,6 +430,19 @@ static struct transport_implementation openssl_transport = {
|
||||
openssl_peek, openssl_errstr, openssl_close
|
||||
};
|
||||
|
||||
struct scwt_context
|
||||
{
|
||||
SSL *ssl;
|
||||
int result;
|
||||
};
|
||||
|
||||
static void
|
||||
ssl_connect_with_timeout_callback(void *arg)
|
||||
{
|
||||
struct scwt_context *ctx = (struct scwt_context *)arg;
|
||||
ctx->result = SSL_connect(ctx->ssl);
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -398,6 +455,7 @@ bool
|
||||
ssl_connect_wget (int fd, const char *hostname)
|
||||
{
|
||||
SSL *conn;
|
||||
struct scwt_context scwt_ctx;
|
||||
struct openssl_transport_context *ctx;
|
||||
|
||||
DEBUGP (("Initiating SSL handshake.\n"));
|
||||
@@ -412,10 +470,10 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
if (! is_valid_ip_address (hostname))
|
||||
{
|
||||
if (! SSL_set_tlsext_host_name (conn, hostname))
|
||||
{
|
||||
DEBUGP (("Failed to set TLS server-name indication."));
|
||||
goto error;
|
||||
}
|
||||
{
|
||||
DEBUGP (("Failed to set TLS server-name indication."));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -425,7 +483,14 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
if (!SSL_set_fd (conn, FD_TO_SOCKET (fd)))
|
||||
goto error;
|
||||
SSL_set_connect_state (conn);
|
||||
if (SSL_connect (conn) <= 0 || conn->state != SSL_ST_OK)
|
||||
|
||||
scwt_ctx.ssl = conn;
|
||||
if (run_with_timeout(opt.read_timeout, ssl_connect_with_timeout_callback,
|
||||
&scwt_ctx)) {
|
||||
DEBUGP (("SSL handshake timed out.\n"));
|
||||
goto timeout;
|
||||
}
|
||||
if (scwt_ctx.result <= 0 || conn->state != SSL_ST_OK)
|
||||
goto error;
|
||||
|
||||
ctx = xnew0 (struct openssl_transport_context);
|
||||
@@ -441,6 +506,7 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
error:
|
||||
DEBUGP (("SSL handshake failed.\n"));
|
||||
print_errors ();
|
||||
timeout:
|
||||
if (conn)
|
||||
SSL_free (conn);
|
||||
return false;
|
||||
@@ -634,7 +700,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
/* Compare and check for NULL attack in ASN1_STRING */
|
||||
if (pattern_match ((char *)name_in_utf8, host) &&
|
||||
(strlen ((char *)name_in_utf8) ==
|
||||
ASN1_STRING_length (name->d.dNSName)))
|
||||
(size_t) ASN1_STRING_length (name->d.dNSName)))
|
||||
{
|
||||
OPENSSL_free (name_in_utf8);
|
||||
break;
|
||||
@@ -657,7 +723,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (alt_name_checked == false)
|
||||
{
|
||||
/* Test commomName */
|
||||
@@ -698,7 +764,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
|
||||
xentry = X509_NAME_get_entry(xname,i);
|
||||
sdata = X509_NAME_ENTRY_get_data(xentry);
|
||||
if (strlen (common_name) != ASN1_STRING_length (sdata))
|
||||
if (strlen (common_name) != (size_t) ASN1_STRING_length (sdata))
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("\
|
||||
%s: certificate common name is invalid (contains a NUL character).\n\
|
||||
|
||||
314
src/options.h
314
src/options.h
@@ -31,237 +31,247 @@ as that of the covered work. */
|
||||
|
||||
struct options
|
||||
{
|
||||
int verbose; /* Are we verbose? (First set to -1,
|
||||
int verbose; /* Are we verbose? (First set to -1,
|
||||
hence not boolean.) */
|
||||
bool quiet; /* Are we quiet? */
|
||||
int ntry; /* Number of tries per URL */
|
||||
bool retry_connrefused; /* Treat CONNREFUSED as non-fatal. */
|
||||
bool background; /* Whether we should work in background. */
|
||||
bool ignore_length; /* Do we heed content-length at all? */
|
||||
bool recursive; /* Are we recursive? */
|
||||
bool spanhost; /* Do we span across hosts in
|
||||
recursion? */
|
||||
bool quiet; /* Are we quiet? */
|
||||
int ntry; /* Number of tries per URL */
|
||||
#ifdef ENABLE_METALINK
|
||||
int n_retries; /* Number of tries per file */
|
||||
#endif
|
||||
char *metalink_file; /* Metalink filename */
|
||||
|
||||
bool retry_connrefused; /* Treat CONNREFUSED as non-fatal. */
|
||||
bool background; /* Whether we should work in background. */
|
||||
bool ignore_length; /* Do we heed content-length at all? */
|
||||
bool recursive; /* Are we recursive? */
|
||||
bool spanhost; /* Do we span across hosts in
|
||||
recursion? */
|
||||
int max_redirect; /* Maximum number of times we'll allow
|
||||
a page to redirect. */
|
||||
bool relative_only; /* Follow only relative links. */
|
||||
bool no_parent; /* Restrict access to the parent
|
||||
directory. */
|
||||
int reclevel; /* Maximum level of recursion */
|
||||
bool dirstruct; /* Do we build the directory structure
|
||||
as we go along? */
|
||||
bool no_dirstruct; /* Do we hate dirstruct? */
|
||||
int cut_dirs; /* Number of directory components to cut. */
|
||||
bool add_hostdir; /* Do we add hostname directory? */
|
||||
bool protocol_directories; /* Whether to prepend "http"/"ftp" to dirs. */
|
||||
bool noclobber; /* Disables clobbering of existing
|
||||
data. */
|
||||
bool unlink; /* remove file before clobbering */
|
||||
char *dir_prefix; /* The top of directory tree */
|
||||
char *lfilename; /* Log filename */
|
||||
char *input_filename; /* Input filename */
|
||||
char *choose_config; /* Specified config file */
|
||||
bool force_html; /* Is the input file an HTML file? */
|
||||
bool relative_only; /* Follow only relative links. */
|
||||
bool no_parent; /* Restrict access to the parent
|
||||
directory. */
|
||||
int reclevel; /* Maximum level of recursion */
|
||||
bool dirstruct; /* Do we build the directory structure
|
||||
as we go along? */
|
||||
bool no_dirstruct; /* Do we hate dirstruct? */
|
||||
int cut_dirs; /* Number of directory components to cut. */
|
||||
bool add_hostdir; /* Do we add hostname directory? */
|
||||
bool protocol_directories; /* Whether to prepend "http"/"ftp" to dirs. */
|
||||
bool noclobber; /* Disables clobbering of existing data. */
|
||||
bool unlink; /* remove file before clobbering */
|
||||
char *dir_prefix; /* The top of directory tree */
|
||||
char *lfilename; /* Log filename */
|
||||
char *input_filename; /* Input filename */
|
||||
char *choose_config; /* Specified config file */
|
||||
bool noconfig; /* Ignore all config files? */
|
||||
bool force_html; /* Is the input file an HTML file? */
|
||||
|
||||
char *default_page; /* Alternative default page (index file) */
|
||||
|
||||
bool spider; /* Is Wget in spider mode? */
|
||||
bool spider; /* Is Wget in spider mode? */
|
||||
|
||||
char **accepts; /* List of patterns to accept. */
|
||||
char **rejects; /* List of patterns to reject. */
|
||||
char **excludes; /* List of excluded FTP directories. */
|
||||
char **includes; /* List of FTP directories to
|
||||
follow. */
|
||||
bool ignore_case; /* Whether to ignore case when
|
||||
matching dirs and files */
|
||||
char **accepts; /* List of patterns to accept. */
|
||||
char **rejects; /* List of patterns to reject. */
|
||||
const char **excludes; /* List of excluded FTP directories. */
|
||||
const char **includes; /* List of FTP directories to
|
||||
follow. */
|
||||
bool ignore_case; /* Whether to ignore case when
|
||||
matching dirs and files */
|
||||
|
||||
char *acceptregex_s; /* Patterns to accept (a regex string). */
|
||||
char *rejectregex_s; /* Patterns to reject (a regex string). */
|
||||
void *acceptregex; /* Patterns to accept (a regex struct). */
|
||||
void *rejectregex; /* Patterns to reject (a regex struct). */
|
||||
char *acceptregex_s; /* Patterns to accept (a regex string). */
|
||||
char *rejectregex_s; /* Patterns to reject (a regex string). */
|
||||
void *acceptregex; /* Patterns to accept (a regex struct). */
|
||||
void *rejectregex; /* Patterns to reject (a regex struct). */
|
||||
enum {
|
||||
#ifdef HAVE_LIBPCRE
|
||||
regex_type_pcre,
|
||||
#endif
|
||||
regex_type_posix
|
||||
} regex_type; /* The regex library. */
|
||||
void *(*regex_compile_fun)(const char *); /* Function to compile a regex. */
|
||||
} regex_type; /* The regex library. */
|
||||
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. */
|
||||
|
||||
char **domains; /* See host.c */
|
||||
char **domains; /* See host.c */
|
||||
char **exclude_domains;
|
||||
bool dns_cache; /* whether we cache DNS lookups. */
|
||||
bool dns_cache; /* whether we cache DNS lookups. */
|
||||
|
||||
char **follow_tags; /* List of HTML tags to recursively follow. */
|
||||
char **ignore_tags; /* List of HTML tags to ignore if recursing. */
|
||||
|
||||
bool follow_ftp; /* Are FTP URL-s followed in recursive
|
||||
retrieving? */
|
||||
bool retr_symlinks; /* Whether we retrieve symlinks in
|
||||
FTP. */
|
||||
char *output_document; /* The output file to which the
|
||||
documents will be printed. */
|
||||
char *warc_filename; /* WARC output filename */
|
||||
char *warc_tempdir; /* WARC temp dir */
|
||||
char *warc_cdx_dedup_filename; /* CDX file to be used for deduplication. */
|
||||
bool follow_ftp; /* Are FTP URL-s followed in recursive
|
||||
retrieving? */
|
||||
bool retr_symlinks; /* Whether we retrieve symlinks in
|
||||
FTP. */
|
||||
char *output_document; /* The output file to which the
|
||||
documents will be printed. */
|
||||
char *warc_filename; /* WARC output filename */
|
||||
char *warc_tempdir; /* WARC temp dir */
|
||||
char *warc_cdx_dedup_filename;/* CDX file to be used for deduplication. */
|
||||
wgint warc_maxsize; /* WARC max archive size */
|
||||
bool warc_compression_enabled; /* For GZIP compression. */
|
||||
bool warc_digests_enabled; /* For SHA1 digests. */
|
||||
bool warc_cdx_enabled; /* Create CDX files? */
|
||||
bool warc_keep_log; /* Store the log file in a WARC record. */
|
||||
char **warc_user_headers; /* User-defined WARC header(s). */
|
||||
bool warc_compression_enabled;/* For GZIP compression. */
|
||||
bool warc_digests_enabled; /* For SHA1 digests. */
|
||||
bool warc_cdx_enabled; /* Create CDX files? */
|
||||
bool warc_keep_log; /* Store the log file in a WARC record. */
|
||||
char **warc_user_headers; /* User-defined WARC header(s). */
|
||||
|
||||
char *user; /* Generic username */
|
||||
char *passwd; /* Generic password */
|
||||
char *user; /* Generic username */
|
||||
char *passwd; /* Generic password */
|
||||
bool ask_passwd; /* Ask for password? */
|
||||
|
||||
bool always_rest; /* Always use REST. */
|
||||
char *ftp_user; /* FTP username */
|
||||
char *ftp_passwd; /* FTP password */
|
||||
bool netrc; /* Whether to read .netrc. */
|
||||
bool ftp_glob; /* FTP globbing */
|
||||
bool ftp_pasv; /* Passive FTP. */
|
||||
bool always_rest; /* Always use REST. */
|
||||
wgint start_pos; /* Start position of a download. */
|
||||
char *ftp_user; /* FTP username */
|
||||
char *ftp_passwd; /* FTP password */
|
||||
bool netrc; /* Whether to read .netrc. */
|
||||
bool ftp_glob; /* FTP globbing */
|
||||
bool ftp_pasv; /* Passive FTP. */
|
||||
|
||||
char *http_user; /* HTTP username. */
|
||||
char *http_passwd; /* HTTP password. */
|
||||
char **user_headers; /* User-defined header(s). */
|
||||
bool http_keep_alive; /* whether we use keep-alive */
|
||||
char *http_user; /* HTTP username. */
|
||||
char *http_passwd; /* HTTP password. */
|
||||
char **user_headers; /* User-defined header(s). */
|
||||
bool http_keep_alive; /* whether we use keep-alive */
|
||||
|
||||
bool use_proxy; /* Do we use proxy? */
|
||||
bool allow_cache; /* Do we allow server-side caching? */
|
||||
bool use_proxy; /* Do we use proxy? */
|
||||
bool allow_cache; /* Do we allow server-side caching? */
|
||||
char *http_proxy, *ftp_proxy, *https_proxy;
|
||||
char **no_proxy;
|
||||
char *base_href;
|
||||
char *progress_type; /* progress indicator type. */
|
||||
char *progress_type; /* progress indicator type. */
|
||||
bool show_progress; /* Show only the progress bar */
|
||||
bool noscroll; /* Don't scroll the filename in the progressbar */
|
||||
char *proxy_user; /*oli*/
|
||||
char *proxy_passwd;
|
||||
|
||||
double read_timeout; /* The read/write timeout. */
|
||||
double dns_timeout; /* The DNS timeout. */
|
||||
double connect_timeout; /* The connect timeout. */
|
||||
double read_timeout; /* The read/write timeout. */
|
||||
double dns_timeout; /* The DNS timeout. */
|
||||
double connect_timeout; /* The connect timeout. */
|
||||
|
||||
bool random_wait; /* vary from 0 .. wait secs by random()? */
|
||||
double wait; /* The wait period between retrievals. */
|
||||
double waitretry; /* The wait period between retries. - HEH */
|
||||
bool use_robots; /* Do we heed robots.txt? */
|
||||
bool random_wait; /* vary from 0 .. wait secs by random()? */
|
||||
double wait; /* The wait period between retrievals. */
|
||||
double waitretry; /* The wait period between retries. - HEH */
|
||||
bool use_robots; /* Do we heed robots.txt? */
|
||||
|
||||
wgint limit_rate; /* Limit the download rate to this
|
||||
many bps. */
|
||||
SUM_SIZE_INT quota; /* Maximum file size to download and
|
||||
store. */
|
||||
wgint limit_rate; /* Limit the download rate to this
|
||||
many bps. */
|
||||
SUM_SIZE_INT quota; /* Maximum file size to download and
|
||||
store. */
|
||||
|
||||
bool server_response; /* Do we print server response? */
|
||||
bool save_headers; /* Do we save headers together with
|
||||
file? */
|
||||
bool content_on_error; /* Do we output the content when the HTTP
|
||||
status code indicates a server error */
|
||||
bool server_response; /* Do we print server response? */
|
||||
bool save_headers; /* Do we save headers together with
|
||||
file? */
|
||||
bool content_on_error; /* Do we output the content when the HTTP
|
||||
status code indicates a server error */
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
bool debug; /* Debugging on/off */
|
||||
#endif
|
||||
bool debug; /* Debugging on/off */
|
||||
|
||||
#ifdef USE_WATT32
|
||||
bool wdebug; /* Watt-32 tcp/ip debugging on/off */
|
||||
#endif
|
||||
|
||||
bool timestamping; /* Whether to use time-stamping. */
|
||||
bool timestamping; /* Whether to use time-stamping. */
|
||||
|
||||
bool backup_converted; /* Do we save pre-converted files as *.orig? */
|
||||
bool backups; /* Are numeric backups made? */
|
||||
bool backup_converted; /* Do we save pre-converted files as *.orig? */
|
||||
int backups; /* Are numeric backups made? */
|
||||
|
||||
char *useragent; /* User-Agent string, which can be set
|
||||
to something other than Wget. */
|
||||
char *referer; /* Naughty Referer, which can be
|
||||
set to something other than
|
||||
NULL. */
|
||||
bool convert_links; /* Will the links be converted
|
||||
locally? */
|
||||
bool remove_listing; /* Do we remove .listing files
|
||||
generated by FTP? */
|
||||
bool htmlify; /* Do we HTML-ify the OS-dependent
|
||||
listings? */
|
||||
char *useragent; /* User-Agent string, which can be set
|
||||
to something other than Wget. */
|
||||
char *referer; /* Naughty Referer, which can be
|
||||
set to something other than
|
||||
NULL. */
|
||||
bool convert_links; /* Will the links be converted
|
||||
locally? */
|
||||
bool remove_listing; /* Do we remove .listing files
|
||||
generated by FTP? */
|
||||
bool htmlify; /* Do we HTML-ify the OS-dependent
|
||||
listings? */
|
||||
|
||||
char *dot_style;
|
||||
wgint dot_bytes; /* How many bytes in a printing
|
||||
dot. */
|
||||
int dots_in_line; /* How many dots in one line. */
|
||||
int dot_spacing; /* How many dots between spacings. */
|
||||
wgint dot_bytes; /* How many bytes in a printing
|
||||
dot. */
|
||||
int dots_in_line; /* How many dots in one line. */
|
||||
int dot_spacing; /* How many dots between spacings. */
|
||||
|
||||
bool delete_after; /* Whether the files will be deleted
|
||||
after download. */
|
||||
bool delete_after; /* Whether the files will be deleted
|
||||
after download. */
|
||||
|
||||
bool adjust_extension; /* Use ".html" extension on all text/html? */
|
||||
bool adjust_extension; /* Use ".html" extension on all text/html? */
|
||||
|
||||
bool page_requisites; /* Whether we need to download all files
|
||||
necessary to display a page properly. */
|
||||
char *bind_address; /* What local IP address to bind to. */
|
||||
bool page_requisites; /* Whether we need to download all files
|
||||
necessary to display a page properly. */
|
||||
char *bind_address; /* What local IP address to bind to. */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
enum {
|
||||
secure_protocol_auto,
|
||||
secure_protocol_sslv2,
|
||||
secure_protocol_sslv3,
|
||||
secure_protocol_tlsv1
|
||||
} secure_protocol; /* type of secure protocol to use. */
|
||||
bool 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). */
|
||||
secure_protocol_tlsv1,
|
||||
secure_protocol_pfs
|
||||
} secure_protocol; /* type of secure protocol to use. */
|
||||
bool 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 {
|
||||
keyfile_pem,
|
||||
keyfile_asn1
|
||||
} cert_type; /* type of client certificate file */
|
||||
} cert_type; /* type of client certificate file */
|
||||
enum keyfile_type
|
||||
private_key_type; /* type of private key file */
|
||||
private_key_type; /* type of private key file */
|
||||
|
||||
char *ca_directory; /* CA directory (hash files) */
|
||||
char *ca_cert; /* CA certificate file to use */
|
||||
char *ca_directory; /* CA directory (hash files) */
|
||||
char *ca_cert; /* CA certificate file to use */
|
||||
|
||||
|
||||
char *random_file; /* file with random data to seed the PRNG */
|
||||
char *egd_file; /* file name of the egd daemon socket */
|
||||
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 */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
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_session_cookies; /* whether session cookies should be
|
||||
saved and loaded. */
|
||||
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_session_cookies; /* whether session cookies should be
|
||||
saved and loaded. */
|
||||
|
||||
char *post_data; /* POST query string */
|
||||
char *post_file_name; /* File to post */
|
||||
char *post_data; /* POST query string */
|
||||
char *post_file_name; /* File to post */
|
||||
char *method; /* HTTP Method to use in Header */
|
||||
char *body_data; /* HTTP Method Data String */
|
||||
char *body_file; /* HTTP Method File */
|
||||
|
||||
enum {
|
||||
restrict_unix,
|
||||
restrict_windows
|
||||
} restrict_files_os; /* file name restriction ruleset. */
|
||||
bool restrict_files_ctrl; /* non-zero if control chars in URLs
|
||||
are restricted from appearing in
|
||||
generated file names. */
|
||||
} restrict_files_os; /* file name restriction ruleset. */
|
||||
bool restrict_files_ctrl; /* non-zero if control chars in URLs
|
||||
are restricted from appearing in
|
||||
generated file names. */
|
||||
bool restrict_files_nonascii; /* non-zero if bytes with values greater
|
||||
than 127 are restricted. */
|
||||
enum {
|
||||
restrict_no_case_restriction,
|
||||
restrict_lowercase,
|
||||
restrict_uppercase
|
||||
} restrict_files_case; /* file name case restriction. */
|
||||
} restrict_files_case; /* file name case restriction. */
|
||||
|
||||
bool strict_comments; /* whether strict SGML comments are
|
||||
enforced. */
|
||||
bool strict_comments; /* whether strict SGML comments are
|
||||
enforced. */
|
||||
|
||||
bool preserve_perm; /* whether remote permissions are used
|
||||
or that what is set by umask. */
|
||||
or that what is set by umask. */
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
bool ipv4_only; /* IPv4 connections have been requested. */
|
||||
bool ipv6_only; /* IPv4 connections have been requested. */
|
||||
bool ipv4_only; /* IPv4 connections have been requested. */
|
||||
bool ipv6_only; /* IPv4 connections have been requested. */
|
||||
#endif
|
||||
enum {
|
||||
prefer_ipv4,
|
||||
prefer_ipv6,
|
||||
prefer_none
|
||||
} prefer_family; /* preferred address family when more
|
||||
than one type is available */
|
||||
} prefer_family; /* preferred address family when more
|
||||
than one type is available */
|
||||
|
||||
bool content_disposition; /* Honor HTTP Content-Disposition header. */
|
||||
bool content_disposition; /* Honor HTTP Content-Disposition header. */
|
||||
bool auth_without_challenge; /* Issue Basic authentication creds without
|
||||
waiting for a challenge. */
|
||||
|
||||
@@ -274,12 +284,14 @@ struct options
|
||||
int ftp_stmlf; /* Force Stream_LF format for binary FTP. */
|
||||
#endif /* def __VMS */
|
||||
|
||||
bool useservertimestamps; /* Update downloaded files' timestamps to
|
||||
match those on server? */
|
||||
bool useservertimestamps; /* Update downloaded files' timestamps to
|
||||
match those on server? */
|
||||
|
||||
bool show_all_dns_entries; /* Show all the DNS entries when resolving a
|
||||
name. */
|
||||
bool show_all_dns_entries; /* Show all the DNS entries when resolving a
|
||||
name. */
|
||||
bool report_bps; /*Output bandwidth in bits format*/
|
||||
|
||||
int jobs; /* How many threads use at the same time. */
|
||||
};
|
||||
|
||||
extern struct options opt;
|
||||
|
||||
407
src/progress.c
407
src/progress.c
@@ -36,38 +36,63 @@ as that of the covered work. */
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_WCHAR_H
|
||||
# include <wchar.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include "progress.h"
|
||||
#include "utils.h"
|
||||
#include "retr.h"
|
||||
#include "ptimer.h"
|
||||
|
||||
struct progress_implementation {
|
||||
const char *name;
|
||||
bool interactive;
|
||||
void *(*create) (wgint, wgint);
|
||||
void *(*create) (const char *, wgint, wgint);
|
||||
void (*update) (void *, wgint, double);
|
||||
void (*draw) (void *, bool);
|
||||
void (*finish) (void *, double);
|
||||
void (*set_params) (const char *);
|
||||
void (*set_params) (char *);
|
||||
};
|
||||
|
||||
/* Necessary forward declarations. */
|
||||
|
||||
static void *dot_create (wgint, wgint);
|
||||
static void *dot_create (const char *, wgint, wgint);
|
||||
static void dot_update (void *, wgint, double);
|
||||
static void dot_finish (void *, double);
|
||||
static void dot_set_params (const char *);
|
||||
static void dot_draw (void *, bool);
|
||||
static void dot_set_params (char *);
|
||||
|
||||
static void *bar_create (wgint, wgint);
|
||||
static void *bar_create (const char *, wgint, wgint);
|
||||
static void bar_update (void *, wgint, double);
|
||||
static void bar_draw (void *, bool);
|
||||
static void bar_finish (void *, double);
|
||||
static void bar_set_params (const char *);
|
||||
static void bar_set_params (char *);
|
||||
|
||||
struct progress_header
|
||||
{
|
||||
struct progress_header *next;
|
||||
};
|
||||
|
||||
static struct progress_header *progress_list = NULL;
|
||||
static struct progress_header *current_progress = NULL;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
# define LOCK_PROGRESS() pthread_mutex_lock (&progress_mutex);
|
||||
# define UNLOCK_PROGRESS() pthread_mutex_unlock (&progress_mutex);
|
||||
#else
|
||||
# define LOCK_PROGRESS()
|
||||
# define UNLOCK_PROGRESS()
|
||||
#endif
|
||||
|
||||
|
||||
static struct progress_implementation implementations[] = {
|
||||
{ "dot", 0, dot_create, dot_update, dot_finish, dot_set_params },
|
||||
{ "bar", 1, bar_create, bar_update, bar_finish, bar_set_params }
|
||||
{ "dot", 0, dot_create, dot_update, dot_draw, dot_finish, dot_set_params },
|
||||
{ "bar", 1, bar_create, bar_update, bar_draw, bar_finish, bar_set_params }
|
||||
};
|
||||
static struct progress_implementation *current_impl;
|
||||
static int current_impl_locked;
|
||||
@@ -85,6 +110,37 @@ static int current_impl_locked;
|
||||
|
||||
#define FALLBACK_PROGRESS_IMPLEMENTATION "dot"
|
||||
|
||||
|
||||
/* Time between screen refreshes will not be shorter than this, so
|
||||
that Wget doesn't swamp the TTY with output. */
|
||||
#define REFRESH_INTERVAL 0.2
|
||||
|
||||
/* Time between screen refreshes the file to show when there are multiple
|
||||
downloads at the same time. */
|
||||
#define REFRESH_SWITCH_FILE 1.5
|
||||
|
||||
/* Assumed screen width if we can't find the real value. */
|
||||
#define DEFAULT_SCREEN_WIDTH 80
|
||||
|
||||
/* Minimum screen width we'll try to work with. If this is too small,
|
||||
create_image will overflow the buffer. */
|
||||
#define MINIMUM_SCREEN_WIDTH 45
|
||||
|
||||
/* The last known screen width. This can be updated by the code that
|
||||
detects that SIGWINCH was received (but it's never updated from the
|
||||
signal handler). */
|
||||
static int screen_width;
|
||||
|
||||
/* A flag that, when set, means SIGWINCH was received. */
|
||||
static volatile sig_atomic_t received_sigwinch;
|
||||
|
||||
static int bp_width; /* screen width we're using at the
|
||||
time the progress gauge was
|
||||
created. this is different from
|
||||
the screen_width global variable in
|
||||
that the latter can be changed by a
|
||||
signal. */
|
||||
|
||||
/* Return true if NAME names a valid progress bar implementation. The
|
||||
characters after the first : will be ignored. */
|
||||
|
||||
@@ -109,7 +165,7 @@ set_progress_implementation (const char *name)
|
||||
{
|
||||
size_t i, namelen;
|
||||
struct progress_implementation *pi = implementations;
|
||||
const char *colon;
|
||||
char *colon;
|
||||
|
||||
if (!name)
|
||||
name = DEFAULT_PROGRESS_IMPLEMENTATION;
|
||||
@@ -151,9 +207,10 @@ progress_schedule_redirect (void)
|
||||
advance. */
|
||||
|
||||
void *
|
||||
progress_create (wgint initial, wgint total)
|
||||
progress_create (const char *f_download, wgint initial, wgint total)
|
||||
{
|
||||
/* Check if the log status has changed under our feet. */
|
||||
struct progress_header *ret;
|
||||
if (output_redirected)
|
||||
{
|
||||
if (!current_impl_locked)
|
||||
@@ -161,7 +218,17 @@ progress_create (wgint initial, wgint total)
|
||||
output_redirected = 0;
|
||||
}
|
||||
|
||||
return current_impl->create (initial, total);
|
||||
ret = current_impl->create (f_download, initial, total);
|
||||
if (ret)
|
||||
{
|
||||
LOCK_PROGRESS ();
|
||||
|
||||
ret->next = progress_list;
|
||||
progress_list = ret;
|
||||
|
||||
UNLOCK_PROGRESS ();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return true if the progress gauge is "interactive", i.e. if it can
|
||||
@@ -170,7 +237,7 @@ progress_create (wgint initial, wgint total)
|
||||
and current update. */
|
||||
|
||||
bool
|
||||
progress_interactive_p (void *progress)
|
||||
progress_interactive_p (void *progress _GL_UNUSED)
|
||||
{
|
||||
return current_impl->interactive;
|
||||
}
|
||||
@@ -181,7 +248,50 @@ progress_interactive_p (void *progress)
|
||||
void
|
||||
progress_update (void *progress, wgint howmuch, double dltime)
|
||||
{
|
||||
static struct ptimer *last_draw = NULL;
|
||||
static struct ptimer *last_switch = NULL;
|
||||
bool force_screen_update = false;
|
||||
|
||||
current_impl->update (progress, howmuch, dltime);
|
||||
LOCK_PROGRESS ();
|
||||
|
||||
if (last_draw == NULL)
|
||||
last_draw = ptimer_new ();
|
||||
if (last_switch == NULL)
|
||||
last_switch = ptimer_new ();
|
||||
|
||||
/* If SIGWINCH (the window size change signal) been received,
|
||||
determine the new screen size and update the screen. */
|
||||
if (received_sigwinch)
|
||||
{
|
||||
int old_width = screen_width;
|
||||
screen_width = determine_screen_width ();
|
||||
if (!screen_width)
|
||||
screen_width = DEFAULT_SCREEN_WIDTH;
|
||||
else if (screen_width < MINIMUM_SCREEN_WIDTH)
|
||||
screen_width = MINIMUM_SCREEN_WIDTH;
|
||||
if (screen_width != old_width)
|
||||
force_screen_update = true;
|
||||
received_sigwinch = 0;
|
||||
}
|
||||
|
||||
if (ptimer_measure (last_draw) >= REFRESH_INTERVAL || force_screen_update)
|
||||
{
|
||||
if (current_progress == NULL)
|
||||
current_progress = progress_list;
|
||||
|
||||
bp_width = screen_width - 1;
|
||||
current_impl->draw (current_progress, force_screen_update);
|
||||
ptimer_reset (last_draw);
|
||||
|
||||
if (ptimer_measure (last_switch) >= REFRESH_SWITCH_FILE)
|
||||
{
|
||||
ptimer_reset (last_switch);
|
||||
current_progress = current_progress->next;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK_PROGRESS ();
|
||||
}
|
||||
|
||||
/* Tell the progress gauge to clean up. Calling this will free the
|
||||
@@ -190,12 +300,38 @@ progress_update (void *progress, wgint howmuch, double dltime)
|
||||
void
|
||||
progress_finish (void *progress, double dltime)
|
||||
{
|
||||
struct progress_header *header = progress;
|
||||
{
|
||||
struct progress_header *it, *prev = NULL;
|
||||
|
||||
LOCK_PROGRESS ();
|
||||
|
||||
for (it = progress_list; it; it = it->next)
|
||||
{
|
||||
if (it == progress)
|
||||
{
|
||||
if (current_progress == progress)
|
||||
current_progress = it->next;
|
||||
|
||||
if (it == progress_list)
|
||||
progress_list = progress_list->next;
|
||||
else
|
||||
prev->next = it->next;
|
||||
break;
|
||||
}
|
||||
prev = it;
|
||||
}
|
||||
|
||||
UNLOCK_PROGRESS ();
|
||||
}
|
||||
current_impl->finish (progress, dltime);
|
||||
}
|
||||
|
||||
/* Dot-printing. */
|
||||
|
||||
struct dot_progress {
|
||||
struct progress_header header;
|
||||
|
||||
wgint initial_length; /* how many bytes have been downloaded
|
||||
previously. */
|
||||
wgint total_length; /* expected total byte count when the
|
||||
@@ -204,6 +340,7 @@ struct dot_progress {
|
||||
int accumulated; /* number of bytes accumulated after
|
||||
the last printed dot */
|
||||
|
||||
double dltime; /* download time so far */
|
||||
int rows; /* number of rows printed so far */
|
||||
int dots; /* number of dots printed in this row */
|
||||
|
||||
@@ -213,7 +350,7 @@ struct dot_progress {
|
||||
/* Dot-progress backend for progress_create. */
|
||||
|
||||
static void *
|
||||
dot_create (wgint initial, wgint total)
|
||||
dot_create (const char *f_download _GL_UNUSED, wgint initial, wgint total)
|
||||
{
|
||||
struct dot_progress *dp = xnew0 (struct dot_progress);
|
||||
dp->initial_length = initial;
|
||||
@@ -237,18 +374,18 @@ dot_create (wgint initial, wgint total)
|
||||
/* Align the [ skipping ... ] line with the dots. To do
|
||||
that, insert the number of spaces equal to the number of
|
||||
digits in the skipped amount in K. */
|
||||
logprintf (LOG_VERBOSE, _("\n%*s[ skipping %sK ]"),
|
||||
logprintf (LOG_PROGRESS, _("\n%*s[ skipping %sK ]"),
|
||||
2 + skipped_k_len, "",
|
||||
number_to_static_string (skipped_k));
|
||||
}
|
||||
|
||||
logprintf (LOG_VERBOSE, "\n%6sK",
|
||||
logprintf (LOG_PROGRESS, "\n%6sK",
|
||||
number_to_static_string (skipped / 1024));
|
||||
for (; remainder >= dot_bytes; remainder -= dot_bytes)
|
||||
{
|
||||
if (dp->dots % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, ",");
|
||||
logputs (LOG_PROGRESS, " ");
|
||||
logputs (LOG_PROGRESS, ",");
|
||||
++dp->dots;
|
||||
}
|
||||
assert (dp->dots < opt.dots_in_line);
|
||||
@@ -289,7 +426,7 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
|
||||
been retrieved. 12.8% will round to 12% because the 13% mark
|
||||
has not yet been reached. 100% is only shown when done. */
|
||||
int percentage = 100.0 * bytes_displayed / dp->total_length;
|
||||
logprintf (LOG_VERBOSE, "%3d%%", percentage);
|
||||
logprintf (LOG_PROGRESS, "%3d%%", percentage);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -306,7 +443,7 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
|
||||
if (dp->rows == dp->initial_length / ROW_BYTES)
|
||||
bytes_this_row -= dp->initial_length % ROW_BYTES;
|
||||
rate = calc_rate (bytes_this_row, dltime - dp->last_timer_value, &units);
|
||||
logprintf (LOG_VERBOSE, " %4.*f%c",
|
||||
logprintf (LOG_PROGRESS, " %4.*f%c",
|
||||
rate >= 99.95 ? 0 : rate >= 9.995 ? 1 : 2,
|
||||
rate, names[units]);
|
||||
dp->last_timer_value = dltime;
|
||||
@@ -323,7 +460,7 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
|
||||
wgint bytes_sofar = bytes_displayed - dp->initial_length;
|
||||
double eta = dltime * bytes_remaining / bytes_sofar;
|
||||
if (eta < INT_MAX - 1)
|
||||
logprintf (LOG_VERBOSE, " %s",
|
||||
logprintf (LOG_PROGRESS, " %s",
|
||||
eta_to_human_short ((int) (eta + 0.5), true));
|
||||
}
|
||||
}
|
||||
@@ -331,10 +468,10 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
|
||||
{
|
||||
/* When done, print the total download time */
|
||||
if (dltime >= 10)
|
||||
logprintf (LOG_VERBOSE, "=%s",
|
||||
logprintf (LOG_PROGRESS, "=%s",
|
||||
eta_to_human_short ((int) (dltime + 0.5), true));
|
||||
else
|
||||
logprintf (LOG_VERBOSE, "=%ss", print_decimal (dltime));
|
||||
logprintf (LOG_PROGRESS, "=%ss", print_decimal (dltime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,23 +479,34 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
|
||||
|
||||
static void
|
||||
dot_update (void *progress, wgint howmuch, double dltime)
|
||||
{
|
||||
struct dot_progress *dp = progress;
|
||||
dp->accumulated += howmuch;
|
||||
dp->dltime = dltime;
|
||||
}
|
||||
|
||||
static void
|
||||
dot_draw (void *progress, bool force)
|
||||
{
|
||||
struct dot_progress *dp = progress;
|
||||
int dot_bytes = opt.dot_bytes;
|
||||
wgint ROW_BYTES = opt.dot_bytes * opt.dots_in_line;
|
||||
|
||||
/* FIXME: support threads. */
|
||||
if (opt.jobs > 1)
|
||||
return;
|
||||
|
||||
log_set_flush (false);
|
||||
|
||||
dp->accumulated += howmuch;
|
||||
for (; dp->accumulated >= dot_bytes; dp->accumulated -= dot_bytes)
|
||||
{
|
||||
if (dp->dots == 0)
|
||||
logprintf (LOG_VERBOSE, "\n%6sK",
|
||||
logprintf (LOG_PROGRESS, "\n%6sK",
|
||||
number_to_static_string (dp->rows * ROW_BYTES / 1024));
|
||||
|
||||
if (dp->dots % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, ".");
|
||||
logputs (LOG_PROGRESS, " ");
|
||||
logputs (LOG_PROGRESS, ".");
|
||||
|
||||
++dp->dots;
|
||||
if (dp->dots >= opt.dots_in_line)
|
||||
@@ -366,7 +514,7 @@ dot_update (void *progress, wgint howmuch, double dltime)
|
||||
++dp->rows;
|
||||
dp->dots = 0;
|
||||
|
||||
print_row_stats (dp, dltime, false);
|
||||
print_row_stats (dp, dp->dltime, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,13 +533,13 @@ dot_finish (void *progress, double dltime)
|
||||
log_set_flush (false);
|
||||
|
||||
if (dp->dots == 0)
|
||||
logprintf (LOG_VERBOSE, "\n%6sK",
|
||||
logprintf (LOG_PROGRESS, "\n%6sK",
|
||||
number_to_static_string (dp->rows * ROW_BYTES / 1024));
|
||||
for (i = dp->dots; i < opt.dots_in_line; i++)
|
||||
{
|
||||
if (i % opt.dot_spacing == 0)
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_VERBOSE, " ");
|
||||
logputs (LOG_PROGRESS, " ");
|
||||
logputs (LOG_PROGRESS, " ");
|
||||
}
|
||||
|
||||
print_row_stats (dp, dltime, true);
|
||||
@@ -407,7 +555,7 @@ dot_finish (void *progress, double dltime)
|
||||
giga. */
|
||||
|
||||
static void
|
||||
dot_set_params (const char *params)
|
||||
dot_set_params (char *params)
|
||||
{
|
||||
if (!params || !*params)
|
||||
params = opt.dot_style;
|
||||
@@ -457,21 +605,6 @@ dot_set_params (const char *params)
|
||||
|
||||
/* "Thermometer" (bar) progress. */
|
||||
|
||||
/* Assumed screen width if we can't find the real value. */
|
||||
#define DEFAULT_SCREEN_WIDTH 80
|
||||
|
||||
/* Minimum screen width we'll try to work with. If this is too small,
|
||||
create_image will overflow the buffer. */
|
||||
#define MINIMUM_SCREEN_WIDTH 45
|
||||
|
||||
/* The last known screen width. This can be updated by the code that
|
||||
detects that SIGWINCH was received (but it's never updated from the
|
||||
signal handler). */
|
||||
static int screen_width;
|
||||
|
||||
/* A flag that, when set, means SIGWINCH was received. */
|
||||
static volatile sig_atomic_t received_sigwinch;
|
||||
|
||||
/* Size of the download speed history ring. */
|
||||
#define DLSPEED_HISTORY_SIZE 20
|
||||
|
||||
@@ -486,33 +619,21 @@ static volatile sig_atomic_t received_sigwinch;
|
||||
download speeds are scratched. */
|
||||
#define STALL_START_TIME 5
|
||||
|
||||
/* Time between screen refreshes will not be shorter than this, so
|
||||
that Wget doesn't swamp the TTY with output. */
|
||||
#define REFRESH_INTERVAL 0.2
|
||||
|
||||
/* Don't refresh the ETA too often to avoid jerkiness in predictions.
|
||||
This allows ETA to change approximately once per second. */
|
||||
#define ETA_REFRESH_INTERVAL 0.99
|
||||
|
||||
struct bar_progress {
|
||||
struct progress_header header;
|
||||
const char *f_download; /* Filename of the downloaded file */
|
||||
wgint initial_length; /* how many bytes have been downloaded
|
||||
previously. */
|
||||
wgint total_length; /* expected total byte count when the
|
||||
download finishes */
|
||||
wgint count; /* bytes downloaded so far */
|
||||
|
||||
double last_screen_update; /* time of the last screen update,
|
||||
measured since the beginning of
|
||||
download. */
|
||||
double dltime; /* download time so far */
|
||||
|
||||
int width; /* screen width we're using at the
|
||||
time the progress gauge was
|
||||
created. this is different from
|
||||
the screen_width global variable in
|
||||
that the latter can be changed by a
|
||||
signal. */
|
||||
char *buffer; /* buffer where the bar "image" is
|
||||
stored. */
|
||||
int tick; /* counter used for drawing the
|
||||
progress bar where the total size
|
||||
is not known. */
|
||||
@@ -547,11 +668,11 @@ struct bar_progress {
|
||||
int last_eta_value;
|
||||
};
|
||||
|
||||
static void create_image (struct bar_progress *, double, bool);
|
||||
static void create_image (struct bar_progress *, char *buffer, double, bool);
|
||||
static void display_image (char *);
|
||||
|
||||
static void *
|
||||
bar_create (wgint initial, wgint total)
|
||||
bar_create (const char *f_download, wgint initial, wgint total)
|
||||
{
|
||||
struct bar_progress *bp = xnew0 (struct bar_progress);
|
||||
|
||||
@@ -562,6 +683,7 @@ bar_create (wgint initial, wgint total)
|
||||
|
||||
bp->initial_length = initial;
|
||||
bp->total_length = total;
|
||||
bp->f_download = f_download;
|
||||
|
||||
/* Initialize screen_width if this hasn't been done or if it might
|
||||
have changed, as indicated by receiving SIGWINCH. */
|
||||
@@ -576,15 +698,11 @@ bar_create (wgint initial, wgint total)
|
||||
}
|
||||
|
||||
/* - 1 because we don't want to use the last screen column. */
|
||||
bp->width = screen_width - 1;
|
||||
/* + enough space for the terminating zero, and hopefully enough room
|
||||
* for multibyte characters. */
|
||||
bp->buffer = xmalloc (bp->width + 100);
|
||||
bp_width = screen_width - 1;
|
||||
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
|
||||
create_image (bp, 0, false);
|
||||
display_image (bp->buffer);
|
||||
bar_draw (bp, false);
|
||||
|
||||
return bp;
|
||||
}
|
||||
@@ -595,8 +713,8 @@ static void
|
||||
bar_update (void *progress, wgint howmuch, double dltime)
|
||||
{
|
||||
struct bar_progress *bp = progress;
|
||||
bool force_screen_update = false;
|
||||
|
||||
bp->dltime = dltime;
|
||||
bp->count += howmuch;
|
||||
if (bp->total_length > 0
|
||||
&& bp->count + bp->initial_length > bp->total_length)
|
||||
@@ -608,33 +726,23 @@ bar_update (void *progress, wgint howmuch, double dltime)
|
||||
bp->total_length = bp->initial_length + bp->count;
|
||||
|
||||
update_speed_ring (bp, howmuch, dltime);
|
||||
}
|
||||
|
||||
/* If SIGWINCH (the window size change signal) been received,
|
||||
determine the new screen size and update the screen. */
|
||||
if (received_sigwinch)
|
||||
static void
|
||||
bar_draw (void *progress, bool force)
|
||||
{
|
||||
struct bar_progress *bp = progress;
|
||||
static char *buffer = NULL;
|
||||
|
||||
if (buffer == NULL)
|
||||
buffer = xmalloc (bp_width + 100);
|
||||
|
||||
if (force)
|
||||
{
|
||||
int old_width = screen_width;
|
||||
screen_width = determine_screen_width ();
|
||||
if (!screen_width)
|
||||
screen_width = DEFAULT_SCREEN_WIDTH;
|
||||
else if (screen_width < MINIMUM_SCREEN_WIDTH)
|
||||
screen_width = MINIMUM_SCREEN_WIDTH;
|
||||
if (screen_width != old_width)
|
||||
{
|
||||
bp->width = screen_width - 1;
|
||||
bp->buffer = xrealloc (bp->buffer, bp->width + 100);
|
||||
force_screen_update = true;
|
||||
}
|
||||
received_sigwinch = 0;
|
||||
buffer = xrealloc (buffer, bp_width + 100);
|
||||
}
|
||||
|
||||
if (dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
|
||||
/* Don't update more often than five times per second. */
|
||||
return;
|
||||
|
||||
create_image (bp, dltime, false);
|
||||
display_image (bp->buffer);
|
||||
bp->last_screen_update = dltime;
|
||||
create_image (bp, buffer, bp->dltime, false);
|
||||
display_image (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -647,12 +755,11 @@ bar_finish (void *progress, double dltime)
|
||||
/* See bar_update() for explanation. */
|
||||
bp->total_length = bp->initial_length + bp->count;
|
||||
|
||||
create_image (bp, dltime, true);
|
||||
display_image (bp->buffer);
|
||||
bar_draw (bp, false);
|
||||
|
||||
logputs (LOG_VERBOSE, "\n\n");
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_PROGRESS, "\n");
|
||||
|
||||
xfree (bp->buffer);
|
||||
xfree (bp);
|
||||
}
|
||||
|
||||
@@ -800,7 +907,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)
|
||||
@@ -845,11 +952,15 @@ get_eta (int *bcd)
|
||||
#ifndef MAX
|
||||
# define MAX(a, b) ((a) >= (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static void
|
||||
create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
create_image (struct bar_progress *bp, char *buffer, double dl_total_time, bool done)
|
||||
{
|
||||
char *p = bp->buffer;
|
||||
const int MAX_FILENAME_LEN = bp_width / 4;
|
||||
char *p = buffer;
|
||||
wgint size = bp->initial_length + bp->count;
|
||||
|
||||
const char *size_grouped = with_thousand_seps (size);
|
||||
@@ -859,9 +970,10 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
int size_grouped_pad; /* Used to pad the field width for size_grouped. */
|
||||
|
||||
struct bar_progress_hist *hist = &bp->hist;
|
||||
int orig_filename_len = strlen (bp->f_download);
|
||||
|
||||
/* The progress bar should look like this:
|
||||
xx% [=======> ] nn,nnn 12.34KB/s eta 36m 51s
|
||||
file xx% [=======> ] nnn.nnK 12.34KB/s eta 36m 51s
|
||||
|
||||
Calculate the geometry. The idea is to assign as much room as
|
||||
possible to the progress bar. The other idea is to never let
|
||||
@@ -870,16 +982,27 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
It would be especially bad for the progress bar to be resized
|
||||
randomly.
|
||||
|
||||
"file " - Downloaded filename - MAX_FILENAME_LEN chars + 1
|
||||
"xx% " or "100%" - percentage - 4 chars
|
||||
" url " - string - MAX MAX_URL_LEN chars + 2
|
||||
"[]" - progress bar decorations - 2 chars
|
||||
" nnn,nnn,nnn" - downloaded bytes - 12 chars or very rarely more
|
||||
" 12.5KB/s" - download rate - 9 chars
|
||||
" nnn.nnK" - downloaded bytes - 7 chars + 1
|
||||
" 12.5KB/s" - download rate - 8 chars + 1
|
||||
" eta 36m 51s" - ETA - 14 chars
|
||||
|
||||
"=====>..." - progress bar - the rest
|
||||
*/
|
||||
int dlbytes_size = 1 + MAX (size_grouped_len, 11);
|
||||
int progress_size = bp->width - (4 + 2 + dlbytes_size + 8 + 14);
|
||||
|
||||
#define PROGRESS_FILENAME_LEN MAX_FILENAME_LEN + 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
|
||||
|
||||
int progress_size = bp_width - (PROGRESS_FILENAME_LEN + PROGRESS_PERCENT_LEN +
|
||||
PROGRESS_DECORAT_LEN + PROGRESS_FILESIZE_LEN +
|
||||
PROGRESS_DWNLOAD_RATE + PROGRESS_ETA_LEN);
|
||||
|
||||
/* The difference between the number of bytes used,
|
||||
and the number of columns used. */
|
||||
@@ -888,6 +1011,27 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
if (progress_size < 5)
|
||||
progress_size = 0;
|
||||
|
||||
if (orig_filename_len <= MAX_FILENAME_LEN)
|
||||
{
|
||||
int padding = MAX_FILENAME_LEN - orig_filename_len;
|
||||
sprintf (p, "%s ", bp->f_download);
|
||||
p += orig_filename_len + 1;
|
||||
for (;padding;padding--)
|
||||
*p++ = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset;
|
||||
|
||||
if (((orig_filename_len > MAX_FILENAME_LEN) && !opt.noscroll) && !done)
|
||||
offset = ((int) bp->tick) % (orig_filename_len - MAX_FILENAME_LEN);
|
||||
else
|
||||
offset = 0;
|
||||
memcpy (p, bp->f_download + offset, MAX_FILENAME_LEN);
|
||||
p += MAX_FILENAME_LEN;
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
/* "xx% " */
|
||||
if (bp->total_length > 0)
|
||||
{
|
||||
@@ -895,7 +1039,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
assert (percentage <= 100);
|
||||
|
||||
if (percentage < 100)
|
||||
sprintf (p, "%2d%% ", percentage);
|
||||
sprintf (p, "%3d%%", percentage);
|
||||
else
|
||||
strcpy (p, "100%");
|
||||
p += 4;
|
||||
@@ -964,13 +1108,20 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
++bp->tick;
|
||||
}
|
||||
|
||||
/* " 234,567,890" */
|
||||
sprintf (p, " %s", size_grouped);
|
||||
/* " 234.56M" */
|
||||
const char * down_size = human_readable (size, 1000, 2);
|
||||
int 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 11 chars for the size_grouped field;
|
||||
/* 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 = 11 - size_grouped_len;
|
||||
for (size_grouped_pad = PROGRESS_FILESIZE_LEN - 7;
|
||||
size_grouped_pad > 0;
|
||||
--size_grouped_pad)
|
||||
{
|
||||
@@ -980,8 +1131,8 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
/* " 12.52Kb/s or 12.52KB/s" */
|
||||
if (hist->total_time > 0 && hist->total_bytes)
|
||||
{
|
||||
static const char *short_units[] = { "B/s", "KB/s", "MB/s", "GB/s" };
|
||||
static const char *short_units_bits[] = { "b/s", "Kb/s", "Mb/s", "Gb/s" };
|
||||
static const char *short_units[] = { " B/s", "KB/s", "MB/s", "GB/s" };
|
||||
static const char *short_units_bits[] = { " b/s", "Kb/s", "Mb/s", "Gb/s" };
|
||||
int units = 0;
|
||||
/* Calculate the download speed using the history ring and
|
||||
recent data that hasn't made it to the ring yet. */
|
||||
@@ -993,7 +1144,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
move_to_end (p);
|
||||
}
|
||||
else
|
||||
APPEND_LITERAL (" --.-K/s");
|
||||
APPEND_LITERAL (" --.-KB/s");
|
||||
|
||||
if (!done)
|
||||
{
|
||||
@@ -1058,7 +1209,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
move_to_end (p);
|
||||
}
|
||||
|
||||
while (p - bp->buffer - bytes_cols_diff - size_grouped_diff < bp->width)
|
||||
while (p - buffer - bytes_cols_diff - size_grouped_diff < bp_width)
|
||||
*p++ = ' ';
|
||||
*p = '\0';
|
||||
}
|
||||
@@ -1070,19 +1221,27 @@ static void
|
||||
display_image (char *buf)
|
||||
{
|
||||
bool old = log_set_save_context (false);
|
||||
logputs (LOG_VERBOSE, "\r");
|
||||
logputs (LOG_VERBOSE, buf);
|
||||
logputs (LOG_PROGRESS, "\r");
|
||||
logputs (LOG_PROGRESS, buf);
|
||||
log_set_save_context (old);
|
||||
}
|
||||
|
||||
static void
|
||||
bar_set_params (const char *params)
|
||||
bar_set_params (char *params)
|
||||
{
|
||||
char *term = getenv ("TERM");
|
||||
|
||||
if (params
|
||||
&& 0 == strcmp (params, "force"))
|
||||
current_impl_locked = 1;
|
||||
if (params)
|
||||
{
|
||||
char *param = strtok (params, ":");
|
||||
do
|
||||
{
|
||||
if (0 == strcmp (param, "force"))
|
||||
current_impl_locked = 1;
|
||||
else if (0 == strcmp (param, "noscroll"))
|
||||
opt.noscroll = true;
|
||||
} while ((param = strtok (NULL, ":")) != NULL);
|
||||
}
|
||||
|
||||
if ((opt.lfilename
|
||||
#ifdef HAVE_ISATTY
|
||||
@@ -1112,7 +1271,7 @@ bar_set_params (const char *params)
|
||||
|
||||
#ifdef SIGWINCH
|
||||
void
|
||||
progress_handle_sigwinch (int sig)
|
||||
progress_handle_sigwinch (int sig _GL_UNUSED)
|
||||
{
|
||||
received_sigwinch = 1;
|
||||
signal (SIGWINCH, progress_handle_sigwinch);
|
||||
|
||||
@@ -35,7 +35,7 @@ bool valid_progress_implementation_p (const char *);
|
||||
void set_progress_implementation (const char *);
|
||||
void progress_schedule_redirect (void);
|
||||
|
||||
void *progress_create (wgint, wgint);
|
||||
void *progress_create (const char *, wgint, wgint);
|
||||
bool progress_interactive_p (void *);
|
||||
void progress_update (void *, wgint, double);
|
||||
void progress_finish (void *, double);
|
||||
|
||||
@@ -31,7 +31,7 @@ as that of the covered work. */
|
||||
#ifndef PTIMER_H
|
||||
#define PTIMER_H
|
||||
|
||||
struct ptimer; /* forward declaration; all struct
|
||||
struct ptimer; /* forward declaration; all struct
|
||||
members are private */
|
||||
|
||||
struct ptimer *ptimer_new (void);
|
||||
|
||||
256
src/recur.c
256
src/recur.c
@@ -1,6 +1,6 @@
|
||||
/* Handling of recursive HTTP retrieving.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -37,6 +37,12 @@ as that of the covered work. */
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#include "multi.h"
|
||||
|
||||
#include "url.h"
|
||||
#include "recur.h"
|
||||
@@ -165,6 +171,27 @@ static bool download_child_p (const struct urlpos *, struct url *, int,
|
||||
static bool descend_redirect_p (const char *, struct url *, int,
|
||||
struct url *, struct hash_table *, struct iri *);
|
||||
|
||||
#if !ENABLE_THREADS
|
||||
# define THREAD_JOIN(...) (0)
|
||||
# define SEM_INIT(...) (0)
|
||||
# define SEM_WAIT(...) (0)
|
||||
#else
|
||||
# define THREAD_JOIN pthread_join
|
||||
# define SEM_INIT sem_init
|
||||
# define SEM_WAIT sem_wait
|
||||
static void *
|
||||
start_retrieve_url (void *arg)
|
||||
{
|
||||
struct s_thread_ctx *ctx = (struct s_thread_ctx *) arg;
|
||||
|
||||
ctx->status = retrieve_url (ctx->url_parsed, ctx->url,
|
||||
&ctx->file, &ctx->redirected,
|
||||
ctx->referer, &ctx->dt,
|
||||
false, ctx->i, true, NULL);
|
||||
ctx->terminated = 1;
|
||||
sem_post (ctx->retr_sem);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Retrieve a part of the web beginning with START_URL. This used to
|
||||
be called "recursive retrieval", because the old function was
|
||||
@@ -191,6 +218,21 @@ uerr_t
|
||||
retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
{
|
||||
uerr_t status = RETROK;
|
||||
struct s_thread_ctx *thread_ctx;
|
||||
char *next_url = NULL, *next_referer;
|
||||
int next_depth;
|
||||
bool next_html_allowed, next_css_allowed;
|
||||
struct iri *next_i = NULL;
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
const int N_THREADS = opt.jobs > 0 ? opt.jobs : 1;
|
||||
sem_t retr_sem;
|
||||
#else
|
||||
const int N_THREADS = 1;
|
||||
void *retr_sem;
|
||||
#endif
|
||||
|
||||
int free_threads = N_THREADS;
|
||||
|
||||
/* The queue of URLs we need to load. */
|
||||
struct url_queue *queue;
|
||||
@@ -213,6 +255,11 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
set_uri_encoding (i, opt.locale, true);
|
||||
#undef COPYSTR
|
||||
|
||||
thread_ctx = calloc (N_THREADS, sizeof *thread_ctx);
|
||||
|
||||
/* FIXME: CHECK FOR ERRORS. */
|
||||
SEM_INIT (&retr_sem, 0, 0);
|
||||
|
||||
queue = url_queue_new ();
|
||||
blacklist = make_string_hash_table (0);
|
||||
|
||||
@@ -225,11 +272,14 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
while (1)
|
||||
{
|
||||
bool descend = false;
|
||||
char *url, *referer, *file = NULL;
|
||||
int depth;
|
||||
bool html_allowed, css_allowed;
|
||||
char *file = NULL;
|
||||
bool is_css = false;
|
||||
bool dash_p_leaf_HTML = false;
|
||||
char *url = NULL, *referer;
|
||||
int depth;
|
||||
bool html_allowed, css_allowed;
|
||||
bool dequed = false;
|
||||
int index = 0;
|
||||
|
||||
if (opt.quota && total_downloaded_bytes > opt.quota)
|
||||
break;
|
||||
@@ -238,10 +288,20 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
|
||||
/* Get the next URL from the queue... */
|
||||
|
||||
if (!url_dequeue (queue, (struct iri **) &i,
|
||||
(const char **)&url, (const char **)&referer,
|
||||
&depth, &html_allowed, &css_allowed))
|
||||
break;
|
||||
if (next_url == NULL)
|
||||
{
|
||||
if (url_dequeue (queue, (struct iri **) &next_i,
|
||||
(const char **)&next_url, (const char **)&next_referer,
|
||||
&next_depth, &next_html_allowed, &next_css_allowed))
|
||||
dequed = true;
|
||||
}
|
||||
|
||||
i = next_i;
|
||||
url = next_url;
|
||||
referer = next_referer;
|
||||
depth = next_depth;
|
||||
html_allowed = next_html_allowed;
|
||||
css_allowed = next_css_allowed;
|
||||
|
||||
/* ...and download it. Note that this download is in most cases
|
||||
unconditional, as download_child_p already makes sure a file
|
||||
@@ -251,40 +311,132 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
and again under URL2, but at a different (possibly smaller)
|
||||
depth, we want the URL's children to be taken into account
|
||||
the second time. */
|
||||
if (dl_url_file_map && hash_table_contains (dl_url_file_map, url))
|
||||
if (dequed && url && dl_url_file_map && hash_table_contains (dl_url_file_map, url))
|
||||
{
|
||||
bool is_css_bool;
|
||||
|
||||
file = xstrdup (hash_table_get (dl_url_file_map, url));
|
||||
|
||||
DEBUGP (("Already downloaded \"%s\", reusing it from \"%s\".\n",
|
||||
url, file));
|
||||
|
||||
/* this sucks, needs to be combined! */
|
||||
if (html_allowed
|
||||
&& downloaded_html_set
|
||||
&& string_set_contains (downloaded_html_set, file))
|
||||
if ((is_css_bool = (css_allowed
|
||||
&& downloaded_css_set
|
||||
&& string_set_contains (downloaded_css_set, file)))
|
||||
|| (html_allowed
|
||||
&& downloaded_html_set
|
||||
&& string_set_contains (downloaded_html_set, file)))
|
||||
{
|
||||
descend = true;
|
||||
is_css = false;
|
||||
}
|
||||
if (css_allowed
|
||||
&& downloaded_css_set
|
||||
&& string_set_contains (downloaded_css_set, file))
|
||||
{
|
||||
descend = true;
|
||||
is_css = true;
|
||||
is_css = is_css_bool;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int dt = 0, url_err;
|
||||
char *redirected = NULL;
|
||||
struct url *url_parsed = url_parse (url, &url_err, i, true);
|
||||
int j;
|
||||
retry:
|
||||
if (! url)
|
||||
{
|
||||
int used = 0;
|
||||
for (j = 0; j < N_THREADS; j++)
|
||||
{
|
||||
if (thread_ctx[j].used)
|
||||
{
|
||||
used = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
status = retrieve_url (url_parsed, url, &file, &redirected, referer,
|
||||
&dt, false, i, true);
|
||||
if (! used)
|
||||
break;
|
||||
}
|
||||
|
||||
if (url && free_threads)
|
||||
{
|
||||
int err;
|
||||
for (j = 0; j < N_THREADS; j++)
|
||||
if (! thread_ctx[j].used)
|
||||
{
|
||||
index = j;
|
||||
free_threads--;
|
||||
thread_ctx[j].used = 1;
|
||||
thread_ctx[j].terminated = 0;
|
||||
break;
|
||||
}
|
||||
assert (j < N_THREADS);
|
||||
|
||||
thread_ctx[index].file = file;
|
||||
thread_ctx[index].referer = referer;
|
||||
thread_ctx[index].dt = 0;
|
||||
thread_ctx[index].i = i;
|
||||
thread_ctx[index].redirected = NULL;
|
||||
thread_ctx[index].range = NULL;
|
||||
thread_ctx[index].url = url;
|
||||
thread_ctx[index].retr_sem = &retr_sem;
|
||||
thread_ctx[index].url_parsed = url_parse (thread_ctx[index].url,
|
||||
&thread_ctx[index].url_err,
|
||||
i, true);
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
err = pthread_create (&thread_ctx[index].thread, NULL,
|
||||
start_retrieve_url, &thread_ctx[index]);
|
||||
#else
|
||||
thread_ctx[index].status = retrieve_url (thread_ctx[index].url_parsed,
|
||||
thread_ctx[index].url,
|
||||
&thread_ctx[index].file,
|
||||
&thread_ctx[index].redirected,
|
||||
thread_ctx[index].referer,
|
||||
&thread_ctx[index].dt,
|
||||
false, i, true,
|
||||
NULL);
|
||||
thread_ctx[index].used = 1;
|
||||
thread_ctx[index].terminated = 1;
|
||||
err = 0;
|
||||
#endif
|
||||
|
||||
if (err == 0)
|
||||
next_url = NULL;
|
||||
else
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "pthread_create: %s\n", strerror (errno));
|
||||
url_free (thread_ctx[index].url_parsed);
|
||||
thread_ctx[index].used = 0;
|
||||
free_threads++;
|
||||
return THREADS_ERR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
for (j = 0; j < N_THREADS; j++)
|
||||
if (thread_ctx[j].used && thread_ctx[j].terminated)
|
||||
{
|
||||
index = j;
|
||||
thread_ctx[j].used = 0;
|
||||
THREAD_JOIN (thread_ctx[j].thread, NULL);
|
||||
free_threads++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
ret = SEM_WAIT (&retr_sem);
|
||||
while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0)
|
||||
return SEM_ERR;
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
file = thread_ctx[index].file;
|
||||
referer = thread_ctx[index].referer;
|
||||
i = thread_ctx[index].i;
|
||||
url = thread_ctx[index].url;
|
||||
|
||||
if (html_allowed && file && status == RETROK
|
||||
&& (dt & RETROKF) && (dt & TEXTHTML))
|
||||
&& (thread_ctx[index].dt & RETROKF) && (thread_ctx[index].dt & TEXTHTML))
|
||||
{
|
||||
descend = true;
|
||||
is_css = false;
|
||||
@@ -294,21 +446,23 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
lots of web servers serve css with an incorrect content type
|
||||
*/
|
||||
if (file && status == RETROK
|
||||
&& (dt & RETROKF) &&
|
||||
((dt & TEXTCSS) || css_allowed))
|
||||
&& (thread_ctx[index].dt & RETROKF) &&
|
||||
((thread_ctx[index].dt & TEXTCSS) || css_allowed)
|
||||
)
|
||||
{
|
||||
descend = true;
|
||||
is_css = true;
|
||||
}
|
||||
|
||||
if (redirected)
|
||||
if (thread_ctx[index].redirected)
|
||||
{
|
||||
/* We have been redirected, possibly to another host, or
|
||||
different path, or wherever. Check whether we really
|
||||
want to follow it. */
|
||||
if (descend)
|
||||
{
|
||||
if (!descend_redirect_p (redirected, url_parsed, depth,
|
||||
if (!descend_redirect_p (thread_ctx[index].redirected,
|
||||
thread_ctx[index].url_parsed, depth,
|
||||
start_url_parsed, blacklist, i))
|
||||
descend = false;
|
||||
else
|
||||
@@ -317,15 +471,15 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
string_set_add (blacklist, url);
|
||||
}
|
||||
|
||||
xfree (url);
|
||||
url = redirected;
|
||||
xfree (thread_ctx[index].url);
|
||||
url = thread_ctx[index].redirected;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfree (url);
|
||||
url = xstrdup (url_parsed->url);
|
||||
xfree (thread_ctx[index].url);
|
||||
url = xstrdup (thread_ctx[index].url_parsed->url);
|
||||
}
|
||||
url_free(url_parsed);
|
||||
url_free(thread_ctx[index].url_parsed);
|
||||
}
|
||||
|
||||
if (opt.spider)
|
||||
@@ -441,11 +595,12 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
register_delete_file (file);
|
||||
}
|
||||
|
||||
#ifndef ENABLE_THREADS
|
||||
xfree (url);
|
||||
xfree_null (referer);
|
||||
xfree_null (file);
|
||||
iri_free (i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If anything is left of the queue due to a premature exit, free it
|
||||
@@ -508,15 +663,16 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
|
||||
}
|
||||
|
||||
/* Several things to check for:
|
||||
1. if scheme is not http, and we don't load it
|
||||
2. check for relative links (if relative_only is set)
|
||||
3. check for domain
|
||||
4. check for no-parent
|
||||
5. check for excludes && includes
|
||||
6. check for suffix
|
||||
7. check for same host (if spanhost is unset), with possible
|
||||
1. if scheme is not https and https_only requested
|
||||
2. if scheme is not http, and we don't load it
|
||||
3. check for relative links (if relative_only is set)
|
||||
4. check for domain
|
||||
5. check for no-parent
|
||||
6. check for excludes && includes
|
||||
7. check for suffix
|
||||
8. check for same host (if spanhost is unset), with possible
|
||||
gethostbyname baggage
|
||||
8. check for robots.txt
|
||||
9. check for robots.txt
|
||||
|
||||
Addendum: If the URL is FTP, and it is to be loaded, only the
|
||||
domain and suffix settings are "stronger".
|
||||
@@ -528,6 +684,14 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
|
||||
More time- and memory- consuming tests should be put later on
|
||||
the list. */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
if (opt.https_only && u->scheme != SCHEME_HTTPS)
|
||||
{
|
||||
DEBUGP (("Not following non-HTTPS links.\n"));
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine whether URL under consideration has a HTTP-like scheme. */
|
||||
u_scheme_like_http = schemes_are_similar_p (u->scheme, SCHEME_HTTP);
|
||||
|
||||
@@ -641,7 +805,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
|
||||
files after downloading or we're just running a spider. */
|
||||
if (opt.delete_after || opt.spider)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, "Removing %s.\n", rfile);
|
||||
logprintf (LOG_VERBOSE, _("Removing %s.\n"), rfile);
|
||||
if (unlink (rfile))
|
||||
logprintf (LOG_NOTQUIET, "unlink: %s\n",
|
||||
strerror (errno));
|
||||
|
||||
13
src/res.c
13
src/res.c
@@ -563,7 +563,7 @@ res_retrieve_file (const char *url, char **file, struct iri *iri)
|
||||
else
|
||||
{
|
||||
err = retrieve_url (url_parsed, robots_url, file, NULL, NULL, NULL,
|
||||
false, i, false);
|
||||
false, i, false, NULL);
|
||||
url_free(url_parsed);
|
||||
}
|
||||
|
||||
@@ -615,11 +615,11 @@ res_cleanup (void)
|
||||
#ifdef TESTING
|
||||
|
||||
const char *
|
||||
test_is_robots_txt_url()
|
||||
test_is_robots_txt_url(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *url;
|
||||
unsigned i;
|
||||
static const struct {
|
||||
const char *url;
|
||||
bool expected_result;
|
||||
} test_array[] = {
|
||||
{ "http://www.yoyodyne.com/robots.txt", true },
|
||||
@@ -627,7 +627,7 @@ test_is_robots_txt_url()
|
||||
{ "http://www.yoyodyne.com/somepath/robots.txt", false },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
mu_assert ("test_is_robots_txt_url: wrong result",
|
||||
is_robots_txt_url (test_array[i].url) == test_array[i].expected_result);
|
||||
@@ -641,4 +641,3 @@ test_is_robots_txt_url()
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
487
src/retr.c
487
src/retr.c
@@ -1,6 +1,6 @@
|
||||
/* File retrieval.
|
||||
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
|
||||
2005, 2006, 2007, 2008, 2009, 2010, 2011, 2014 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
@@ -37,7 +37,22 @@ as that of the covered work. */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef ENABLE_THREADS
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
#ifdef ENABLE_METALINK
|
||||
#include <metalink/metalink_parser.h>
|
||||
#include <metalink/metalink_types.h>
|
||||
#ifdef VMS
|
||||
# include <unixio.h> /* For delete(). */
|
||||
#endif
|
||||
|
||||
#include "metalink.h"
|
||||
#endif
|
||||
#ifdef ENABLE_THREADS
|
||||
#include "multi.h"
|
||||
#endif
|
||||
#include "exits.h"
|
||||
#include "utils.h"
|
||||
#include "retr.h"
|
||||
@@ -54,6 +69,17 @@ as that of the covered work. */
|
||||
#include "html-url.h"
|
||||
#include "iri.h"
|
||||
|
||||
#ifdef ENABLE_METALINK
|
||||
static pthread_mutex_t pconn_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
#define IS_IO_ERROR(status) status == FOPENERR || status == WRITEFAILED || \
|
||||
status == UNLINKERR || status == FWRITEERR || status == FOPEN_EXCL_ERR
|
||||
|
||||
#define PCONN_LOCK() pthread_mutex_lock (&pconn_mutex)
|
||||
|
||||
#define PCONN_UNLOCK() pthread_mutex_unlock (&pconn_mutex)
|
||||
#endif
|
||||
|
||||
/* Total size of downloaded files. Used to enforce quota. */
|
||||
SUM_SIZE_INT total_downloaded_bytes;
|
||||
|
||||
@@ -141,8 +167,8 @@ limit_bandwidth (wgint bytes, struct ptimer *timer)
|
||||
amount of data and decrease SKIP. Increment *TOTAL by the amount
|
||||
of data written. If OUT2 is not NULL, also write BUF to OUT2.
|
||||
In case of error writing to OUT, -1 is returned. In case of error
|
||||
writing to OUT2, -2 is returned. In case of any other error,
|
||||
1 is returned. */
|
||||
writing to OUT2, -2 is returned. Return 1 if the whole BUF was
|
||||
skipped. */
|
||||
|
||||
static int
|
||||
write_data (FILE *out, FILE *out2, const char *buf, int bufsize,
|
||||
@@ -223,7 +249,7 @@ write_data (FILE *out, FILE *out2, const char *buf, int bufsize,
|
||||
data to OUT2, -3 is returned. */
|
||||
|
||||
int
|
||||
fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
fd_read_body (const char *downloaded_filename, int fd, FILE *out, wgint toread, wgint startpos,
|
||||
wgint *qtyread, wgint *qtywritten, double *elapsed, int flags,
|
||||
FILE *out2)
|
||||
{
|
||||
@@ -259,13 +285,13 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
if (flags & rb_skip_startpos)
|
||||
skip = startpos;
|
||||
|
||||
if (opt.verbose)
|
||||
if (opt.show_progress)
|
||||
{
|
||||
/* If we're skipping STARTPOS bytes, pass 0 as the INITIAL
|
||||
argument to progress_create because the indicator doesn't
|
||||
(yet) know about "skipping" data. */
|
||||
wgint start = skip ? 0 : startpos;
|
||||
progress = progress_create (start, start + toread);
|
||||
progress = progress_create (downloaded_filename, start, start + toread);
|
||||
progress_interactive = progress_interactive_p (progress);
|
||||
}
|
||||
|
||||
@@ -376,7 +402,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
{
|
||||
sum_read += ret;
|
||||
int write_res = write_data (out, out2, dlbuf, ret, &skip, &sum_written);
|
||||
if (write_res != 0)
|
||||
if (write_res < 0)
|
||||
{
|
||||
ret = (write_res == -3) ? -3 : -2;
|
||||
goto out;
|
||||
@@ -408,7 +434,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
if (progress)
|
||||
progress_update (progress, ret, ptimer_read (timer));
|
||||
#ifdef WINDOWS
|
||||
if (toread > 0 && !opt.quiet)
|
||||
if (toread > 0 && opt.show_progress)
|
||||
ws_percenttitle (100.0 *
|
||||
(startpos + sum_read) / (startpos + toread));
|
||||
#endif
|
||||
@@ -584,7 +610,7 @@ fd_read_hunk (int fd, hunk_terminator_t terminator, long sizehint, long maxsize)
|
||||
}
|
||||
|
||||
static const char *
|
||||
line_terminator (const char *start, const char *peeked, int peeklen)
|
||||
line_terminator (const char *start _GL_UNUSED, const char *peeked, int peeklen)
|
||||
{
|
||||
const char *p = memchr (peeked, '\n', peeklen);
|
||||
if (p)
|
||||
@@ -646,7 +672,7 @@ calc_rate (wgint bytes, double secs, int *units)
|
||||
{
|
||||
double dlrate;
|
||||
double bibyte = 1000.0;
|
||||
|
||||
|
||||
if (!opt.report_bps)
|
||||
bibyte = 1024.0;
|
||||
|
||||
@@ -677,20 +703,23 @@ calc_rate (wgint bytes, double secs, int *units)
|
||||
}
|
||||
|
||||
|
||||
#define SUSPEND_POST_DATA do { \
|
||||
post_data_suspended = true; \
|
||||
saved_post_data = opt.post_data; \
|
||||
saved_post_file_name = opt.post_file_name; \
|
||||
opt.post_data = NULL; \
|
||||
opt.post_file_name = NULL; \
|
||||
#define SUSPEND_METHOD do { \
|
||||
method_suspended = true; \
|
||||
saved_body_data = opt.body_data; \
|
||||
saved_body_file_name = opt.body_file; \
|
||||
saved_method = opt.method; \
|
||||
opt.body_data = NULL; \
|
||||
opt.body_file = NULL; \
|
||||
opt.method = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define RESTORE_POST_DATA do { \
|
||||
if (post_data_suspended) \
|
||||
#define RESTORE_METHOD do { \
|
||||
if (method_suspended) \
|
||||
{ \
|
||||
opt.post_data = saved_post_data; \
|
||||
opt.post_file_name = saved_post_file_name; \
|
||||
post_data_suspended = false; \
|
||||
opt.body_data = saved_body_data; \
|
||||
opt.body_file = saved_body_file_name; \
|
||||
opt.method = saved_method; \
|
||||
method_suspended = false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -705,7 +734,7 @@ static char *getproxy (struct url *);
|
||||
uerr_t
|
||||
retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
char **newloc, const char *refurl, int *dt, bool recursive,
|
||||
struct iri *iri, bool register_status)
|
||||
struct iri *iri, bool register_status, struct range *segment_range)
|
||||
{
|
||||
uerr_t result;
|
||||
char *url;
|
||||
@@ -718,9 +747,10 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
char *local_file;
|
||||
int redirection_count = 0;
|
||||
|
||||
bool post_data_suspended = false;
|
||||
char *saved_post_data = NULL;
|
||||
char *saved_post_file_name = NULL;
|
||||
bool method_suspended = false;
|
||||
char *saved_body_data = NULL;
|
||||
char *saved_method = NULL;
|
||||
char *saved_body_file_name = NULL;
|
||||
|
||||
/* If dt is NULL, use local storage. */
|
||||
if (!dt)
|
||||
@@ -731,8 +761,13 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
url = xstrdup (origurl);
|
||||
if (newloc)
|
||||
*newloc = NULL;
|
||||
|
||||
#ifndef ENABLE_METALINK
|
||||
/* Note that, each and every call to retrieve_url(), except the ones made by
|
||||
functions relevant to metalink support, the value of *file is NULL. */
|
||||
if (file)
|
||||
*file = NULL;
|
||||
#endif
|
||||
|
||||
if (!refurl)
|
||||
refurl = opt.referer;
|
||||
@@ -742,7 +777,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
|
||||
result = NOCONERROR;
|
||||
mynewloc = NULL;
|
||||
local_file = NULL;
|
||||
local_file = *file;
|
||||
proxy_url = NULL;
|
||||
|
||||
proxy = getproxy (u);
|
||||
@@ -761,7 +796,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
proxy, error);
|
||||
xfree (url);
|
||||
xfree (error);
|
||||
RESTORE_POST_DATA;
|
||||
RESTORE_METHOD;
|
||||
result = PROXERR;
|
||||
goto bail;
|
||||
}
|
||||
@@ -770,10 +805,11 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
logprintf (LOG_NOTQUIET, _("Error in proxy URL %s: Must be HTTP.\n"), proxy);
|
||||
url_free (proxy_url);
|
||||
xfree (url);
|
||||
RESTORE_POST_DATA;
|
||||
RESTORE_METHOD;
|
||||
result = PROXERR;
|
||||
goto bail;
|
||||
}
|
||||
free (proxy);
|
||||
}
|
||||
|
||||
if (u->scheme == SCHEME_HTTP
|
||||
@@ -783,7 +819,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
|| (proxy_url && proxy_url->scheme == SCHEME_HTTP))
|
||||
{
|
||||
result = http_loop (u, orig_parsed, &mynewloc, &local_file, refurl, dt,
|
||||
proxy_url, iri);
|
||||
proxy_url, iri, segment_range);
|
||||
}
|
||||
else if (u->scheme == SCHEME_FTP)
|
||||
{
|
||||
@@ -794,7 +830,7 @@ 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, &local_file, dt, proxy_url, recursive, glob, segment_range);
|
||||
recursive = oldrec;
|
||||
|
||||
/* There is a possibility of having HTTP being redirected to
|
||||
@@ -838,6 +874,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
iri->utf8_encode = opt.enable_iri;
|
||||
set_content_encoding (iri, NULL);
|
||||
xfree_null (iri->orig_url);
|
||||
iri->orig_url = NULL;
|
||||
|
||||
/* Now, see if this new location makes sense. */
|
||||
newloc_parsed = url_parse (mynewloc, &up_error_code, iri, true);
|
||||
@@ -853,7 +890,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
xfree (url);
|
||||
xfree (mynewloc);
|
||||
xfree (error);
|
||||
RESTORE_POST_DATA;
|
||||
RESTORE_METHOD;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
@@ -875,7 +912,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
}
|
||||
xfree (url);
|
||||
xfree (mynewloc);
|
||||
RESTORE_POST_DATA;
|
||||
RESTORE_METHOD;
|
||||
result = WRONGCODE;
|
||||
goto bail;
|
||||
}
|
||||
@@ -894,12 +931,12 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
index page; that redirection is clearly a GET. We "suspend"
|
||||
POST data for the duration of the redirections, and restore
|
||||
it when we're done.
|
||||
|
||||
RFC2616 HTTP/1.1 introduces code 307 Temporary Redirect
|
||||
specifically to preserve the method of the request.
|
||||
*/
|
||||
if (result != NEWLOCATION_KEEP_POST && !post_data_suspended)
|
||||
SUSPEND_POST_DATA;
|
||||
|
||||
RFC2616 HTTP/1.1 introduces code 307 Temporary Redirect
|
||||
specifically to preserve the method of the request.
|
||||
*/
|
||||
if (result != NEWLOCATION_KEEP_POST && !method_suspended)
|
||||
SUSPEND_METHOD;
|
||||
|
||||
goto redirected;
|
||||
}
|
||||
@@ -932,10 +969,10 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
register_redirection (origurl, u->url);
|
||||
|
||||
if (*dt & TEXTHTML)
|
||||
register_html (local_file);
|
||||
register_html ("",local_file);
|
||||
|
||||
if (*dt & TEXTCSS)
|
||||
register_css (local_file);
|
||||
register_css ("",local_file);
|
||||
}
|
||||
|
||||
if (file)
|
||||
@@ -962,7 +999,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
xfree (url);
|
||||
}
|
||||
|
||||
RESTORE_POST_DATA;
|
||||
RESTORE_METHOD;
|
||||
|
||||
bail:
|
||||
if (register_status)
|
||||
@@ -996,7 +1033,6 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
if (url_valid_scheme (url))
|
||||
{
|
||||
int dt,url_err;
|
||||
uerr_t status;
|
||||
struct url *url_parsed = url_parse (url, &url_err, iri, true);
|
||||
if (!url_parsed)
|
||||
{
|
||||
@@ -1010,7 +1046,7 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
opt.base_href = xstrdup (url);
|
||||
|
||||
status = retrieve_url (url_parsed, url, &url_file, NULL, NULL, &dt,
|
||||
false, iri, true);
|
||||
false, iri, true, NULL);
|
||||
url_free (url_parsed);
|
||||
|
||||
if (!url_file || (status != RETROK))
|
||||
@@ -1022,7 +1058,7 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
/* 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);
|
||||
set_uri_encoding (iri, iri->content_encoding, false);
|
||||
|
||||
/* Reset UTF-8 encode status */
|
||||
iri->utf8_encode = opt.enable_iri;
|
||||
@@ -1034,69 +1070,302 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
else
|
||||
input_file = (char *) file;
|
||||
|
||||
url_list = (html ? get_urls_html (input_file, NULL, NULL, iri)
|
||||
: get_urls_file (input_file));
|
||||
#ifdef ENABLE_METALINK
|
||||
mlink *mlink = parse_metalink(input_file);
|
||||
|
||||
xfree_null (url_file);
|
||||
|
||||
for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
|
||||
if(opt.metalink_file && mlink)
|
||||
{
|
||||
char *filename = NULL, *new_file = NULL;
|
||||
int dt;
|
||||
struct iri *tmpiri = iri_dup (iri);
|
||||
struct url *parsed_url = NULL;
|
||||
int i, j, r, ranges_covered, chunk_size, url_err, retries, ret, dt=0;
|
||||
pthread_t thread;
|
||||
sem_t retr_sem;
|
||||
uerr_t status;
|
||||
mlink_file* file;
|
||||
mlink_resource *resource;
|
||||
struct s_thread_ctx *thread_ctx;
|
||||
|
||||
if (cur_url->ignore_when_downloading)
|
||||
continue;
|
||||
/* Wget supports HTTP&FTP, and Metalink supports MD5, SHA1 & SHA-256. */
|
||||
elect_resources (mlink);
|
||||
elect_checksums (mlink);
|
||||
|
||||
if (opt.quota && total_downloaded_bytes > opt.quota)
|
||||
init_temp_files();
|
||||
init_ranges ();
|
||||
thread_ctx = malloc (opt.jobs * (sizeof *thread_ctx));
|
||||
|
||||
retries = 0;
|
||||
file = mlink->files;
|
||||
while (file)
|
||||
{
|
||||
status = QUOTEXC;
|
||||
break;
|
||||
memset (thread_ctx, '\0', opt.jobs * (sizeof *thread_ctx));
|
||||
|
||||
/* If chunk_size is too small, set it equal to MIN_CHUNK_SIZE. */
|
||||
chunk_size = (file->size) / opt.jobs;
|
||||
if(chunk_size < MIN_CHUNK_SIZE)
|
||||
chunk_size = MIN_CHUNK_SIZE;
|
||||
|
||||
j = fill_ranges_data (file->num_of_res, file->size, chunk_size);
|
||||
|
||||
/* If chunk_size was set to MIN_CHUNK_SIZE, opt.jobs should be corrected. */
|
||||
if (j < opt.jobs)
|
||||
opt.jobs = j;
|
||||
|
||||
name_temp_files ();
|
||||
|
||||
sem_init (&retr_sem, 0, 0);
|
||||
j = ranges_covered = 0;
|
||||
resource = file->resources;
|
||||
|
||||
/* Assign values to thread_ctx[] elements and spawn threads that will
|
||||
conduct the download. */
|
||||
for (r = 0; r < opt.jobs; ++r)
|
||||
{
|
||||
if (!resource)
|
||||
{
|
||||
j = 0;
|
||||
resource = file->resources;
|
||||
}
|
||||
|
||||
thread_ctx[r].referer = NULL;
|
||||
thread_ctx[r].redirected = NULL;
|
||||
thread_ctx[r].dt = dt;
|
||||
thread_ctx[r].i = iri;
|
||||
thread_ctx[r].url = resource->url;
|
||||
thread_ctx[r].retr_sem = &retr_sem;
|
||||
|
||||
ret = spawn_thread (thread_ctx, r, j);
|
||||
if (ret)
|
||||
{
|
||||
/* If thread creation is unsuccessful */
|
||||
char *error = url_error (thread_ctx[r].url, thread_ctx[r].url_err);
|
||||
logprintf (LOG_NOTQUIET, "%s: %s.\n", thread_ctx[r].url, error);
|
||||
xfree (error);
|
||||
free (thread_ctx);
|
||||
clean_range_res_data ();
|
||||
clean_ranges ();
|
||||
clean_temp_files ();
|
||||
return URLERROR;
|
||||
}
|
||||
++j;
|
||||
resource = resource->next;
|
||||
}
|
||||
|
||||
/* Until all the ranges are covered, collect threads. */
|
||||
while (ranges_covered < opt.jobs)
|
||||
{
|
||||
r = collect_thread (&retr_sem, thread_ctx);
|
||||
++ranges_covered;
|
||||
|
||||
status = thread_ctx[r].status;
|
||||
|
||||
/* Check return status of thread for errors. */
|
||||
if (IS_IO_ERROR (status))
|
||||
{
|
||||
/* The error is of type WGET_EXIT_IO_FAIL given in exits.c.
|
||||
No fallbacking is needed for this type of error. */
|
||||
inform_exit_status (status);
|
||||
break;
|
||||
}
|
||||
else if(status != RETROK)
|
||||
{
|
||||
int error_severity;
|
||||
PCONN_LOCK ();
|
||||
|
||||
/* Pick the least severe error.*/
|
||||
error_severity = get_exit_status();
|
||||
inform_exit_status ((thread_ctx[r].range)->status_least_severe);
|
||||
if(get_exit_status() != error_severity)
|
||||
(thread_ctx[r].range)->status_least_severe = status;
|
||||
|
||||
PCONN_UNLOCK ();
|
||||
|
||||
/* Look for resource from which downloading this range is not
|
||||
tried. */
|
||||
j = 0;
|
||||
resource = file->resources;
|
||||
while (j < file->num_of_res)
|
||||
{
|
||||
if (!((thread_ctx[r].range)->resources)[j])
|
||||
break;
|
||||
++j;
|
||||
resource = resource -> next;
|
||||
}
|
||||
/* If there is such a resource, then update the range values
|
||||
to try that not-tried resource and spawn thread.
|
||||
If all the resources are exhausted, stop collecting the
|
||||
threads, as the download failed. */
|
||||
if (j < file->num_of_res)
|
||||
{
|
||||
if ((thread_ctx[r].range)->bytes_covered)
|
||||
{
|
||||
thread_ctx[r].url = resource->url;
|
||||
(thread_ctx[r].range)->first_byte =
|
||||
(thread_ctx[r].range)->bytes_covered;
|
||||
(thread_ctx[r].range)->bytes_covered = 0;
|
||||
}
|
||||
--ranges_covered;
|
||||
ret = spawn_thread (thread_ctx, r, j);
|
||||
if (ret)
|
||||
{
|
||||
/* If thread creation is unsuccessful */
|
||||
char *error = url_error (thread_ctx[r].url, thread_ctx[r].url_err);
|
||||
logprintf (LOG_NOTQUIET, "%s: %s.\n", thread_ctx[r].url, error);
|
||||
xfree (error);
|
||||
free (thread_ctx);
|
||||
clean_range_res_data ();
|
||||
clean_ranges ();
|
||||
clean_temp_files ();
|
||||
return URLERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sem_destroy(&retr_sem);
|
||||
|
||||
/* Check the download status. If conditions are suitable, retry. */
|
||||
if (status != RETROK)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Downloading %s failed. Chunk %d could "
|
||||
"not be downloaded from any of the "
|
||||
"URLs listed in metalink file.\n"),
|
||||
file->name, r);
|
||||
|
||||
/* Failed downloads should only be retried if the error causing
|
||||
the failure is not an IO error. */
|
||||
if (!(IS_IO_ERROR((thread_ctx[r].range)->status_least_severe)))
|
||||
{
|
||||
if(retries < opt.n_retries)
|
||||
{
|
||||
logprintf (LOG_VERBOSE,
|
||||
_("Retrying to download(%s). (TRY #%d)\n"),
|
||||
file->name, ++retries + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *file_path;
|
||||
int res;
|
||||
/* Form the actual file to be downloaded and verify hash. */
|
||||
file_path = malloc((opt.dir_prefix ? strlen(opt.dir_prefix) : 0)
|
||||
+ strlen(file->name) + (sizeof "/"));
|
||||
if(opt.dir_prefix)
|
||||
sprintf(file_path, "%s/%s", opt.dir_prefix, file->name);
|
||||
else
|
||||
sprintf(file_path, "%s", file->name);
|
||||
mkalldirs(file_path);
|
||||
merge_temp_files(file_path);
|
||||
res = verify_file_hash(file_path, file->checksums);
|
||||
free(file_path);
|
||||
if(!res)
|
||||
{
|
||||
++*count;
|
||||
logprintf (LOG_VERBOSE, _("Verifying(%s) succeeded.\n"),
|
||||
file->name);
|
||||
}
|
||||
else if(res < 0)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Verifying(%s) failed.\n"),
|
||||
file->name);
|
||||
if(retries < opt.n_retries)
|
||||
{
|
||||
logprintf (LOG_VERBOSE,
|
||||
_("Retrying to download(%s). (TRY #%d)\n"),
|
||||
file->name, ++retries + 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete_temp_files();
|
||||
|
||||
clean_range_res_data();
|
||||
if (opt.quota && total_downloaded_bytes > opt.quota)
|
||||
{
|
||||
status = QUOTEXC;
|
||||
break;
|
||||
}
|
||||
file = file->next;
|
||||
}
|
||||
|
||||
parsed_url = url_parse (cur_url->url->url, NULL, tmpiri, true);
|
||||
free(thread_ctx);
|
||||
clean_ranges ();
|
||||
clean_temp_files ();
|
||||
delete_mlink(mlink);
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
url_list = (html ? get_urls_html (input_file, NULL, NULL, iri)
|
||||
: get_urls_file (input_file));
|
||||
|
||||
if ((opt.recursive || opt.page_requisites)
|
||||
&& (cur_url->url->scheme != SCHEME_FTP || getproxy (cur_url->url)))
|
||||
xfree_null (url_file);
|
||||
|
||||
for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
|
||||
{
|
||||
int old_follow_ftp = opt.follow_ftp;
|
||||
char *filename = NULL, *new_file = NULL;
|
||||
int dt;
|
||||
struct iri *tmpiri = iri_dup (iri);
|
||||
struct url *parsed_url = NULL;
|
||||
|
||||
/* Turn opt.follow_ftp on in case of recursive FTP retrieval */
|
||||
if (cur_url->url->scheme == SCHEME_FTP)
|
||||
opt.follow_ftp = 1;
|
||||
if (cur_url->ignore_when_downloading)
|
||||
continue;
|
||||
|
||||
status = retrieve_tree (parsed_url ? parsed_url : cur_url->url,
|
||||
if (opt.quota && total_downloaded_bytes > opt.quota)
|
||||
{
|
||||
status = QUOTEXC;
|
||||
break;
|
||||
}
|
||||
|
||||
parsed_url = url_parse (cur_url->url->url, NULL, tmpiri, true);
|
||||
|
||||
char *proxy = getproxy (cur_url->url);
|
||||
if ((opt.recursive || opt.page_requisites)
|
||||
&& (cur_url->url->scheme != SCHEME_FTP || 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)
|
||||
opt.follow_ftp = 1;
|
||||
|
||||
status = retrieve_tree (parsed_url ? parsed_url : cur_url->url,
|
||||
tmpiri);
|
||||
|
||||
opt.follow_ftp = old_follow_ftp;
|
||||
}
|
||||
else
|
||||
status = retrieve_url (parsed_url ? parsed_url : cur_url->url,
|
||||
cur_url->url->url, &filename,
|
||||
&new_file, NULL, &dt, opt.recursive, tmpiri,
|
||||
true);
|
||||
opt.follow_ftp = old_follow_ftp;
|
||||
}
|
||||
else
|
||||
status = retrieve_url (parsed_url ? parsed_url : cur_url->url,
|
||||
cur_url->url->url, &filename,
|
||||
&new_file, NULL, &dt, opt.recursive, tmpiri,
|
||||
true, NULL);
|
||||
free(proxy);
|
||||
|
||||
if (parsed_url)
|
||||
url_free (parsed_url);
|
||||
if (parsed_url)
|
||||
url_free (parsed_url);
|
||||
|
||||
if (filename && opt.delete_after && file_exists_p (filename))
|
||||
{
|
||||
DEBUGP (("\
|
||||
if (filename && opt.delete_after && file_exists_p (filename))
|
||||
{
|
||||
DEBUGP (("\
|
||||
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));
|
||||
dt &= ~RETROKF;
|
||||
logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
|
||||
if (unlink (filename))
|
||||
logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
|
||||
dt &= ~RETROKF;
|
||||
}
|
||||
|
||||
xfree_null (new_file);
|
||||
xfree_null (filename);
|
||||
iri_free (tmpiri);
|
||||
}
|
||||
|
||||
xfree_null (new_file);
|
||||
xfree_null (filename);
|
||||
iri_free (tmpiri);
|
||||
/* Free the linked list of URL-s. */
|
||||
free_urlpos (url_list);
|
||||
#ifdef ENABLE_METALINK
|
||||
}
|
||||
|
||||
/* Free the linked list of URL-s. */
|
||||
free_urlpos (url_list);
|
||||
#endif
|
||||
|
||||
iri_free (iri);
|
||||
|
||||
@@ -1177,7 +1446,16 @@ free_urlpos (struct urlpos *l)
|
||||
void
|
||||
rotate_backups(const char *fname)
|
||||
{
|
||||
int maxlen = strlen (fname) + 1 + numdigit (opt.backups) + 1;
|
||||
#ifdef __VMS
|
||||
# define SEP "_"
|
||||
# define AVS ";*" /* All-version suffix. */
|
||||
# define AVSL (sizeof (AVS) - 1)
|
||||
#else
|
||||
# define SEP "."
|
||||
# define AVSL 0
|
||||
#endif
|
||||
|
||||
int maxlen = strlen (fname) + sizeof (SEP) + numdigit (opt.backups) + AVSL;
|
||||
char *from = (char *)alloca (maxlen);
|
||||
char *to = (char *)alloca (maxlen);
|
||||
struct_stat sb;
|
||||
@@ -1189,12 +1467,24 @@ rotate_backups(const char *fname)
|
||||
|
||||
for (i = opt.backups; i > 1; i--)
|
||||
{
|
||||
sprintf (from, "%s.%d", fname, i - 1);
|
||||
sprintf (to, "%s.%d", fname, i);
|
||||
#ifdef VMS
|
||||
/* Delete (all versions of) any existing max-suffix file, to avoid
|
||||
* creating multiple versions of it. (On VMS, rename() will
|
||||
* create a new version of an existing destination file, not
|
||||
* destroy/overwrite it.)
|
||||
*/
|
||||
if (i == opt.backups)
|
||||
{
|
||||
sprintf (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);
|
||||
}
|
||||
|
||||
sprintf (to, "%s.%d", fname, 1);
|
||||
sprintf (to, "%s%s%d", fname, SEP, 1);
|
||||
rename(fname, to);
|
||||
}
|
||||
|
||||
@@ -1207,7 +1497,6 @@ getproxy (struct url *u)
|
||||
{
|
||||
char *proxy = NULL;
|
||||
char *rewritten_url;
|
||||
static char rewritten_storage[1024];
|
||||
|
||||
if (!opt.use_proxy)
|
||||
return NULL;
|
||||
@@ -1237,13 +1526,9 @@ getproxy (struct url *u)
|
||||
getproxy() to return static storage. */
|
||||
rewritten_url = rewrite_shorthand_url (proxy);
|
||||
if (rewritten_url)
|
||||
{
|
||||
strncpy (rewritten_storage, rewritten_url, sizeof (rewritten_storage));
|
||||
rewritten_storage[sizeof (rewritten_storage) - 1] = '\0';
|
||||
proxy = rewritten_storage;
|
||||
}
|
||||
return rewritten_url;
|
||||
|
||||
return proxy;
|
||||
return strdup(proxy);
|
||||
}
|
||||
|
||||
/* Returns true if URL would be downloaded through a proxy. */
|
||||
@@ -1254,7 +1539,9 @@ url_uses_proxy (struct url * u)
|
||||
bool ret;
|
||||
if (!u)
|
||||
return false;
|
||||
ret = getproxy (u) != NULL;
|
||||
char *proxy = getproxy (u);
|
||||
ret = proxy != NULL;
|
||||
free(proxy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ enum {
|
||||
rb_chunked_transfer_encoding = 4
|
||||
};
|
||||
|
||||
int fd_read_body (int, FILE *, wgint, wgint, wgint *, wgint *, double *, int, FILE *);
|
||||
int fd_read_body (const char *, int, FILE *, wgint, wgint, wgint *, wgint *, double *, int, FILE *);
|
||||
|
||||
typedef const char *(*hunk_terminator_t) (const char *, const char *, int);
|
||||
|
||||
@@ -58,7 +58,7 @@ char *fd_read_hunk (int, hunk_terminator_t, long, long);
|
||||
char *fd_read_line (int);
|
||||
|
||||
uerr_t retrieve_url (struct url *, const char *, char **, char **,
|
||||
const char *, int *, bool, struct iri *, bool);
|
||||
const char *, int *, bool, struct iri *, bool, struct range *);
|
||||
uerr_t retrieve_from_file (const char *, bool, int *);
|
||||
|
||||
const char *retr_rate (wgint, double);
|
||||
|
||||
@@ -45,7 +45,7 @@ static struct hash_table *nonexisting_urls_set;
|
||||
|
||||
/* Cleanup the data structures associated with this file. */
|
||||
|
||||
static void
|
||||
void
|
||||
spider_cleanup (void)
|
||||
{
|
||||
if (nonexisting_urls_set)
|
||||
@@ -97,4 +97,3 @@ print_broken_links (void)
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
@@ -34,5 +34,6 @@ as that of the covered work. */
|
||||
#define visited_url(a,b)
|
||||
void nonexisting_url (const char *);
|
||||
void print_broken_links (void);
|
||||
void spider_cleanup (void);
|
||||
|
||||
#endif /* SPIDER_H */
|
||||
|
||||
77
src/sysdep.h
77
src/sysdep.h
@@ -78,35 +78,15 @@ as that of the covered work. */
|
||||
These have to be after the above namespace tweaks, but before any
|
||||
non-preprocessor code. */
|
||||
|
||||
#if HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
#elif defined WINDOWS
|
||||
# include <malloc.h>
|
||||
# ifndef alloca
|
||||
# define alloca _alloca
|
||||
# endif
|
||||
#elif defined __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#elif defined _AIX
|
||||
# define alloca __alloca
|
||||
#else
|
||||
# include <stddef.h>
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *alloca (size_t);
|
||||
#endif
|
||||
#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>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
/* Compaq C V6.5-303 (dtk) on HP Tru64 UNIX V5.1B (Rev. 2650) needs: */
|
||||
# include <stdint.h>
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
/* Windows doesn't have some functions normally found on Unix-like
|
||||
@@ -121,34 +101,6 @@ void *alloca (size_t);
|
||||
/* Provided by gnulib on systems that don't have it: */
|
||||
# include <stdbool.h>
|
||||
|
||||
/* Needed for compilation under OS/2 and MSDOS */
|
||||
#if defined(__EMX__) || defined(MSDOS)
|
||||
# ifndef S_ISLNK
|
||||
# define S_ISLNK(m) 0
|
||||
# endif
|
||||
# ifndef lstat
|
||||
# define lstat stat
|
||||
# endif
|
||||
#endif /* __EMX__ || MSDOS */
|
||||
|
||||
/* Reportedly, stat() macros are broken on some old systems. Those
|
||||
systems will have to fend for themselves, as I will not introduce
|
||||
new code to handle it.
|
||||
|
||||
However, I will add code for *missing* macros, and the following
|
||||
are reportedly missing from many systems. */
|
||||
#ifndef S_ISLNK
|
||||
# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#endif
|
||||
#ifndef S_ISDIR
|
||||
# define S_ISDIR(m) (((m) & (_S_IFMT)) == (_S_IFDIR))
|
||||
#endif
|
||||
#ifndef S_ISREG
|
||||
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
||||
#endif
|
||||
|
||||
/* These are needed so we can #define struct_stat to struct _stati64
|
||||
under Windows. */
|
||||
#ifndef struct_stat
|
||||
# define struct_stat struct stat
|
||||
#endif
|
||||
@@ -156,6 +108,8 @@ void *alloca (size_t);
|
||||
# define struct_fstat struct stat
|
||||
#endif
|
||||
|
||||
#include <intprops.h>
|
||||
|
||||
/* For CHAR_BIT, LONG_MAX, etc. */
|
||||
#include <limits.h>
|
||||
|
||||
@@ -163,9 +117,6 @@ void *alloca (size_t);
|
||||
# define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
/* From gnulib, simplified to assume a signed type. */
|
||||
#define TYPE_MAXIMUM(t) ((t) (~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
|
||||
|
||||
/* These are defined in cmpt.c if missing, so we must declare
|
||||
them. */
|
||||
#ifndef HAVE_STRCASECMP
|
||||
@@ -212,23 +163,7 @@ int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
# define SYSTEM_FNMATCH
|
||||
#endif
|
||||
|
||||
#ifdef SYSTEM_FNMATCH
|
||||
# include <fnmatch.h>
|
||||
#else /* not SYSTEM_FNMATCH */
|
||||
/* Define fnmatch flags. Undef them first to avoid warnings in case
|
||||
an evil library include chose to include system fnmatch.h. */
|
||||
# undef FNM_PATHNAME
|
||||
# undef FNM_NOESCAPE
|
||||
# undef FNM_PERIOD
|
||||
# undef FNM_NOMATCH
|
||||
|
||||
# define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
|
||||
# define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
|
||||
# define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
|
||||
# define FNM_NOMATCH 1
|
||||
|
||||
int fnmatch (const char *, const char *, int);
|
||||
#endif
|
||||
#include <fnmatch.h>
|
||||
|
||||
/* Provide sig_atomic_t if the system doesn't. */
|
||||
#ifndef HAVE_SIG_ATOMIC_T
|
||||
|
||||
16
src/test.c
16
src/test.c
@@ -28,7 +28,12 @@ Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#include "wget.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef ENABLE_NLS
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "test.h"
|
||||
|
||||
@@ -69,10 +74,18 @@ all_tests()
|
||||
char *program_name; /* Needed by lib/error.c. */
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
main (int argc _GL_UNUSED, char *argv[])
|
||||
{
|
||||
const char *result;
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
/* Set the current locale. */
|
||||
setlocale (LC_ALL, "");
|
||||
/* Set the text message domain. */
|
||||
bindtextdomain ("wget", LOCALEDIR);
|
||||
textdomain ("wget");
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
program_name = argv[0];
|
||||
|
||||
result = all_tests();
|
||||
@@ -94,4 +107,3 @@ main (int argc, char *argv[])
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
11
src/test.h
11
src/test.h
@@ -45,9 +45,18 @@ do { \
|
||||
|
||||
extern int tests_run;
|
||||
|
||||
const char *test_parse_content_disposition(void);
|
||||
const char *test_commands_sorted(void);
|
||||
const char *test_cmd_spec_restrict_file_names(void);
|
||||
const char *test_is_robots_txt_url(void);
|
||||
const char *test_path_simplify (void);
|
||||
const char *test_append_uri_pathel(void);
|
||||
const char *test_are_urls_equal(void);
|
||||
const char *test_subdir_p(void);
|
||||
const char *test_dir_matches_p(void);
|
||||
|
||||
#endif /* TEST_H */
|
||||
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
207
src/url.c
207
src/url.c
@@ -169,7 +169,7 @@ static const unsigned char urlchr_table[256] =
|
||||
The transformation is done in place. If you need the original
|
||||
string intact, make a copy before calling this function. */
|
||||
|
||||
static void
|
||||
void
|
||||
url_unescape (char *s)
|
||||
{
|
||||
char *t = s; /* t - tortoise */
|
||||
@@ -618,12 +618,12 @@ lowercase_str (char *str)
|
||||
}
|
||||
|
||||
static const char *
|
||||
init_seps (enum url_scheme scheme)
|
||||
init_seps (enum url_scheme scheme, char *seps)
|
||||
{
|
||||
static char seps[8] = ":/";
|
||||
char *p = seps + 2;
|
||||
int flags = supported_schemes[scheme].flags;
|
||||
|
||||
strcpy (seps, ":/");
|
||||
if (flags & scm_has_params)
|
||||
*p++ = ';';
|
||||
if (flags & scm_has_query)
|
||||
@@ -676,6 +676,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
const char *params_b, *params_e;
|
||||
const char *query_b, *query_e;
|
||||
const char *fragment_b, *fragment_e;
|
||||
char seps_b[8];
|
||||
|
||||
int port;
|
||||
char *user = NULL, *passwd = NULL;
|
||||
@@ -701,7 +702,10 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
if (!iri->utf8_encode)
|
||||
new_url = NULL;
|
||||
else
|
||||
iri->orig_url = xstrdup (url);
|
||||
{
|
||||
iri->orig_url = xstrdup (url);
|
||||
percent_encode = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX XXX Could that change introduce (security) bugs ??? XXX XXX*/
|
||||
@@ -736,7 +740,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
/* Initialize separators for optional parts of URL, depending on the
|
||||
scheme. For example, FTP has params, and HTTP and HTTPS have
|
||||
query string and fragment. */
|
||||
seps = init_seps (scheme);
|
||||
seps = init_seps (scheme, seps_b);
|
||||
|
||||
host_b = p;
|
||||
|
||||
@@ -1245,12 +1249,16 @@ mkalldirs (const char *path)
|
||||
The idea is to have a convenient and efficient way to construct a
|
||||
string by having various functions append data to it. Instead of
|
||||
passing the obligatory BASEVAR, SIZEVAR and TAILPOS to all the
|
||||
functions in questions, we pass the pointer to this struct. */
|
||||
functions in questions, we pass the pointer to this struct.
|
||||
|
||||
Functions that write to the members in this struct must make sure
|
||||
that base remains null terminated by calling append_null().
|
||||
*/
|
||||
|
||||
struct growable {
|
||||
char *base;
|
||||
int size;
|
||||
int tail;
|
||||
int size; /* memory allocated */
|
||||
int tail; /* string length */
|
||||
};
|
||||
|
||||
/* Ensure that the string can accept APPEND_COUNT more characters past
|
||||
@@ -1268,28 +1276,45 @@ struct growable {
|
||||
/* Move the tail position by APPEND_COUNT characters. */
|
||||
#define TAIL_INCR(r, append_count) ((r)->tail += append_count)
|
||||
|
||||
/* Append the string STR to DEST. NOTICE: the string in DEST is not
|
||||
terminated. */
|
||||
|
||||
/* Append NULL to DEST. */
|
||||
static void
|
||||
append_null (struct growable *dest)
|
||||
{
|
||||
GROW (dest, 1);
|
||||
*TAIL (dest) = 0;
|
||||
}
|
||||
|
||||
/* Append CH to DEST. */
|
||||
static void
|
||||
append_char (char ch, struct growable *dest)
|
||||
{
|
||||
if (ch)
|
||||
{
|
||||
GROW (dest, 1);
|
||||
*TAIL (dest) = ch;
|
||||
TAIL_INCR (dest, 1);
|
||||
}
|
||||
|
||||
append_null (dest);
|
||||
}
|
||||
|
||||
/* Append the string STR to DEST. */
|
||||
static void
|
||||
append_string (const char *str, struct growable *dest)
|
||||
{
|
||||
int l = strlen (str);
|
||||
GROW (dest, l);
|
||||
memcpy (TAIL (dest), str, l);
|
||||
TAIL_INCR (dest, l);
|
||||
|
||||
if (l)
|
||||
{
|
||||
GROW (dest, l);
|
||||
memcpy (TAIL (dest), str, l);
|
||||
TAIL_INCR (dest, l);
|
||||
}
|
||||
|
||||
append_null (dest);
|
||||
}
|
||||
|
||||
/* Append CH to DEST. For example, append_char (0, DEST)
|
||||
zero-terminates DEST. */
|
||||
|
||||
static void
|
||||
append_char (char ch, struct growable *dest)
|
||||
{
|
||||
GROW (dest, 1);
|
||||
*TAIL (dest) = ch;
|
||||
TAIL_INCR (dest, 1);
|
||||
}
|
||||
|
||||
enum {
|
||||
filechr_not_unix = 1, /* unusable on Unix, / and \0 */
|
||||
@@ -1361,6 +1386,7 @@ UWC, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
|
||||
query, normally '?'. Since Windows cannot handle '?' as part of
|
||||
file name, we use '@' instead there. */
|
||||
#define FN_QUERY_SEP (opt.restrict_files_os != restrict_windows ? '?' : '@')
|
||||
#define FN_QUERY_SEP_STR (opt.restrict_files_os != restrict_windows ? "?" : "@")
|
||||
|
||||
/* Quote path element, characters in [b, e), as file name, and append
|
||||
the quoted string to DEST. Each character is quoted as per
|
||||
@@ -1454,6 +1480,7 @@ append_uri_pathel (const char *b, const char *e, bool escaped,
|
||||
}
|
||||
|
||||
TAIL_INCR (dest, outlen);
|
||||
append_null (dest);
|
||||
}
|
||||
|
||||
/* Append to DEST the directory structure that corresponds the
|
||||
@@ -1494,22 +1521,28 @@ append_dir_structure (const struct url *u, struct growable *dest)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a unique file name that matches the given URL as good as
|
||||
/* Return a unique file name that matches the given URL as well as
|
||||
possible. Does not create directories on the file system. */
|
||||
|
||||
char *
|
||||
url_file_name (const struct url *u, char *replaced_filename)
|
||||
{
|
||||
struct growable fnres; /* stands for "file name result" */
|
||||
struct growable temp_fnres;
|
||||
|
||||
const char *u_file;
|
||||
char *fname, *unique;
|
||||
char *fname, *unique, *fname_len_check;
|
||||
const char *index_filename = "index.html"; /* The default index file is index.html */
|
||||
size_t max_length;
|
||||
|
||||
fnres.base = NULL;
|
||||
fnres.size = 0;
|
||||
fnres.tail = 0;
|
||||
|
||||
temp_fnres.base = NULL;
|
||||
temp_fnres.size = 0;
|
||||
temp_fnres.tail = 0;
|
||||
|
||||
/* If an alternative index file was defined, change index_filename */
|
||||
if (opt.default_page)
|
||||
index_filename = opt.default_page;
|
||||
@@ -1555,43 +1588,87 @@ url_file_name (const struct url *u, char *replaced_filename)
|
||||
|
||||
if (!replaced_filename)
|
||||
{
|
||||
/* Add the file name. */
|
||||
if (fnres.tail)
|
||||
append_char ('/', &fnres);
|
||||
/* Create the filename. */
|
||||
u_file = *u->file ? u->file : index_filename;
|
||||
append_uri_pathel (u_file, u_file + strlen (u_file), false, &fnres);
|
||||
|
||||
/* Append "?query" to the file name, even if empty */
|
||||
/* Append "?query" to the file name, even if empty,
|
||||
* and create fname_len_check. */
|
||||
if (u->query)
|
||||
{
|
||||
append_char (FN_QUERY_SEP, &fnres);
|
||||
append_uri_pathel (u->query, u->query + strlen (u->query),
|
||||
true, &fnres);
|
||||
}
|
||||
fname_len_check = concat_strings (u_file, FN_QUERY_SEP_STR, u->query, NULL);
|
||||
else
|
||||
fname_len_check = strdupdelim (u_file, u_file + strlen (u_file));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fnres.tail)
|
||||
append_char ('/', &fnres);
|
||||
u_file = replaced_filename;
|
||||
append_uri_pathel (u_file, u_file + strlen (u_file), false, &fnres);
|
||||
fname_len_check = strdupdelim (u_file, u_file + strlen (u_file));
|
||||
}
|
||||
|
||||
/* Zero-terminate the file name. */
|
||||
append_char ('\0', &fnres);
|
||||
append_uri_pathel (fname_len_check,
|
||||
fname_len_check + strlen (fname_len_check), false, &temp_fnres);
|
||||
|
||||
/* Zero-terminate the temporary file name. */
|
||||
append_char ('\0', &temp_fnres);
|
||||
|
||||
/* Check that the length of the file name is acceptable. */
|
||||
#ifdef WINDOWS
|
||||
if (MAX_PATH > (fnres.tail + CHOMP_BUFFER + 2))
|
||||
{
|
||||
max_length = MAX_PATH - (fnres.tail + CHOMP_BUFFER + 2);
|
||||
/* FIXME: In Windows a filename is usually limited to 255 characters.
|
||||
To really be accurate you could call GetVolumeInformation() to get
|
||||
lpMaximumComponentLength
|
||||
*/
|
||||
if (max_length > 255)
|
||||
{
|
||||
max_length = 255;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
max_length = 0;
|
||||
}
|
||||
#else
|
||||
max_length = get_max_length (fnres.base, fnres.tail, _PC_NAME_MAX) - CHOMP_BUFFER;
|
||||
#endif
|
||||
if (max_length > 0 && strlen (temp_fnres.base) > max_length)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "The name is too long, %lu chars total.\n",
|
||||
(unsigned long) strlen (temp_fnres.base));
|
||||
logprintf (LOG_NOTQUIET, "Trying to shorten...\n");
|
||||
|
||||
/* Shorten the file name. */
|
||||
temp_fnres.base[max_length] = '\0';
|
||||
|
||||
logprintf (LOG_NOTQUIET, "New name is %s.\n", temp_fnres.base);
|
||||
}
|
||||
|
||||
free (fname_len_check);
|
||||
|
||||
/* The filename has already been 'cleaned' by append_uri_pathel() above. So,
|
||||
* just append it. */
|
||||
if (fnres.tail)
|
||||
append_char ('/', &fnres);
|
||||
append_string (temp_fnres.base, &fnres);
|
||||
|
||||
fname = fnres.base;
|
||||
|
||||
/* Make a final check that the path length is acceptable? */
|
||||
/* TODO: check fnres.base for path length problem */
|
||||
|
||||
free (temp_fnres.base);
|
||||
|
||||
/* Check the cases in which the unique extensions are not used:
|
||||
1) Clobbering is turned off (-nc).
|
||||
2) Retrieval with regetting.
|
||||
3) Timestamping is used.
|
||||
4) Hierarchy is built.
|
||||
5) Backups are specified.
|
||||
|
||||
The exception is the case when file does exist and is a
|
||||
directory (see `mkalldirs' for explanation). */
|
||||
|
||||
if ((opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct)
|
||||
if (ALLOW_CLOBBER
|
||||
&& !(file_exists_p (fname) && !file_non_directory_p (fname)))
|
||||
{
|
||||
unique = fname;
|
||||
@@ -1715,10 +1792,11 @@ path_end (const char *url)
|
||||
{
|
||||
enum url_scheme scheme = url_scheme (url);
|
||||
const char *seps;
|
||||
char seps_b[8];
|
||||
if (scheme == SCHEME_INVALID)
|
||||
scheme = SCHEME_HTTP; /* use http semantics for rel links */
|
||||
/* +2 to ignore the first two separators ':' and '/' */
|
||||
seps = init_seps (scheme) + 2;
|
||||
seps = init_seps (scheme, seps_b) + 2;
|
||||
return strpbrk_or_eos (url, seps);
|
||||
}
|
||||
|
||||
@@ -1960,7 +2038,7 @@ url_string (const struct url *url, enum url_auth_mode auth_mode)
|
||||
if (url->passwd)
|
||||
{
|
||||
if (auth_mode == URL_AUTH_HIDE_PASSWD)
|
||||
quoted_passwd = HIDDEN_PASSWORD;
|
||||
quoted_passwd = (char *) HIDDEN_PASSWORD;
|
||||
else
|
||||
quoted_passwd = url_escape_allow_passthrough (url->passwd);
|
||||
}
|
||||
@@ -2129,7 +2207,7 @@ ps (char *path)
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
run_test (char *test, char *expected_result, enum url_scheme scheme,
|
||||
run_test (const char *test, const char *expected_result, enum url_scheme scheme,
|
||||
bool expected_change)
|
||||
{
|
||||
char *test_copy = xstrdup (test);
|
||||
@@ -2158,8 +2236,8 @@ run_test (char *test, char *expected_result, enum url_scheme scheme,
|
||||
const char *
|
||||
test_path_simplify (void)
|
||||
{
|
||||
static struct {
|
||||
char *test, *result;
|
||||
static const struct {
|
||||
const char *test, *result;
|
||||
enum url_scheme scheme;
|
||||
bool should_modify;
|
||||
} tests[] = {
|
||||
@@ -2191,15 +2269,16 @@ test_path_simplify (void)
|
||||
{ "a/b/../../c", "c", SCHEME_HTTP, true },
|
||||
{ "./a/../b", "b", SCHEME_HTTP, true }
|
||||
};
|
||||
int i;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < countof (tests); i++)
|
||||
{
|
||||
const char *message;
|
||||
char *test = tests[i].test;
|
||||
char *expected_result = tests[i].result;
|
||||
const char *test = tests[i].test;
|
||||
const char *expected_result = tests[i].result;
|
||||
enum url_scheme scheme = tests[i].scheme;
|
||||
bool expected_change = tests[i].should_modify;
|
||||
|
||||
message = run_test (test, expected_result, scheme, expected_change);
|
||||
if (message) return message;
|
||||
}
|
||||
@@ -2207,19 +2286,19 @@ test_path_simplify (void)
|
||||
}
|
||||
|
||||
const char *
|
||||
test_append_uri_pathel()
|
||||
test_append_uri_pathel(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *original_url;
|
||||
char *input;
|
||||
unsigned i;
|
||||
static const struct {
|
||||
const char *original_url;
|
||||
const char *input;
|
||||
bool escaped;
|
||||
char *expected_result;
|
||||
const char *expected_result;
|
||||
} test_array[] = {
|
||||
{ "http://www.yoyodyne.com/path/", "somepage.html", false, "http://www.yoyodyne.com/path/somepage.html" },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
struct growable dest;
|
||||
const char *p = test_array[i].input;
|
||||
@@ -2228,7 +2307,6 @@ test_append_uri_pathel()
|
||||
|
||||
append_string (test_array[i].original_url, &dest);
|
||||
append_uri_pathel (p, p + strlen(p), test_array[i].escaped, &dest);
|
||||
append_char ('\0', &dest);
|
||||
|
||||
mu_assert ("test_append_uri_pathel: wrong result",
|
||||
strcmp (dest.base, test_array[i].expected_result) == 0);
|
||||
@@ -2237,13 +2315,13 @@ test_append_uri_pathel()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char*
|
||||
test_are_urls_equal()
|
||||
const char *
|
||||
test_are_urls_equal(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *url1;
|
||||
char *url2;
|
||||
unsigned i;
|
||||
static const struct {
|
||||
const char *url1;
|
||||
const char *url2;
|
||||
bool expected_result;
|
||||
} test_array[] = {
|
||||
{ "http://www.adomain.com/apath/", "http://www.adomain.com/apath/", true },
|
||||
@@ -2254,7 +2332,7 @@ test_are_urls_equal()
|
||||
{ "http://www.adomain.com/path%2f", "http://www.adomain.com/path/", false },
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(test_array)/sizeof(test_array[0]); ++i)
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
mu_assert ("test_are_urls_equal: wrong result",
|
||||
are_urls_equal (test_array[i].url1, test_array[i].url2) == test_array[i].expected_result);
|
||||
@@ -2268,4 +2346,3 @@ test_are_urls_equal()
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
25
src/url.h
25
src/url.h
@@ -37,6 +37,22 @@ as that of the covered work. */
|
||||
#define DEFAULT_FTP_PORT 21
|
||||
#define DEFAULT_HTTPS_PORT 443
|
||||
|
||||
/* This represents how many characters less than the OS max name length a file
|
||||
* should be. More precisely, a file name should be at most
|
||||
* (NAME_MAX - CHOMP_BUFFER) characters in length. This number was arrived at
|
||||
* by adding the lengths of all possible strings that could be appended to a
|
||||
* file name later in the code (e.g. ".orig", ".html", etc.). This is
|
||||
* hopefully plenty of extra characters, but I am not guaranteeing that a file
|
||||
* name will be of the proper length by the time the code wants to open a
|
||||
* file descriptor. */
|
||||
#define CHOMP_BUFFER 19
|
||||
|
||||
/* The flags that allow clobbering the file (opening with "wb").
|
||||
Defined here to avoid repetition later. #### This will require
|
||||
rework. */
|
||||
#define ALLOW_CLOBBER (opt.noclobber || opt.always_rest || opt.timestamping \
|
||||
|| opt.dirstruct || opt.output_document || opt.backups > 0)
|
||||
|
||||
/* Specifies how, or whether, user auth information should be included
|
||||
* in URLs regenerated from URL parse structures. */
|
||||
enum url_auth_mode {
|
||||
@@ -60,11 +76,11 @@ enum url_scheme {
|
||||
/* Structure containing info on a URL. */
|
||||
struct url
|
||||
{
|
||||
char *url; /* Original URL */
|
||||
enum url_scheme scheme; /* URL scheme */
|
||||
char *url; /* Original URL */
|
||||
enum url_scheme scheme; /* URL scheme */
|
||||
|
||||
char *host; /* Extracted hostname */
|
||||
int port; /* Port number */
|
||||
char *host; /* Extracted hostname */
|
||||
int port; /* Port number */
|
||||
|
||||
/* URL components (URL-quoted). */
|
||||
char *path;
|
||||
@@ -85,6 +101,7 @@ struct url
|
||||
|
||||
char *url_escape (const char *);
|
||||
char *url_escape_unsafe_and_reserved (const char *);
|
||||
void url_unescape (char *);
|
||||
|
||||
struct url *url_parse (const char *, int *, struct iri *iri, bool percent_encode);
|
||||
char *url_error (const char *, int);
|
||||
|
||||
242
src/utils.c
242
src/utils.c
@@ -65,9 +65,7 @@ as that of the covered work. */
|
||||
|
||||
/* For TIOCGWINSZ and friends: */
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
# include <termios.h>
|
||||
#endif
|
||||
#include <termios.h>
|
||||
|
||||
/* Needed for Unix version of run_with_timeout. */
|
||||
#include <signal.h>
|
||||
@@ -100,7 +98,9 @@ as that of the covered work. */
|
||||
#include "test.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
#include "exits.h"
|
||||
|
||||
static void _Noreturn
|
||||
memfatal (const char *context, long attempted_size)
|
||||
{
|
||||
/* Make sure we don't try to store part of the log line, and thus
|
||||
@@ -123,7 +123,7 @@ memfatal (const char *context, long attempted_size)
|
||||
exec_name, context, attempted_size);
|
||||
}
|
||||
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
/* Character property table for (re-)escaping VMS ODS5 extended file
|
||||
@@ -471,7 +471,7 @@ fork_to_background (void)
|
||||
{
|
||||
/* parent, error */
|
||||
perror ("fork");
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
@@ -479,14 +479,17 @@ fork_to_background (void)
|
||||
printf (_("Continuing in background, pid %d.\n"), (int) pid);
|
||||
if (logfile_changed)
|
||||
printf (_("Output will be written to %s.\n"), quote (opt.lfilename));
|
||||
exit (0); /* #### should we use _exit()? */
|
||||
exit (WGET_EXIT_SUCCESS); /* #### should we use _exit()? */
|
||||
}
|
||||
|
||||
/* child: give up the privileges and keep running. */
|
||||
setsid ();
|
||||
freopen ("/dev/null", "r", stdin);
|
||||
freopen ("/dev/null", "w", stdout);
|
||||
freopen ("/dev/null", "w", stderr);
|
||||
if (freopen ("/dev/null", "r", stdin) == NULL)
|
||||
DEBUGP (("Failed to redirect stdin to /dev/null.\n"));
|
||||
if (freopen ("/dev/null", "w", stdout) == NULL)
|
||||
DEBUGP (("Failed to redirect stdout to /dev/null.\n"));
|
||||
if (freopen ("/dev/null", "w", stderr) == NULL)
|
||||
DEBUGP (("Failed to redirect stderr to /dev/null.\n"));
|
||||
}
|
||||
#endif /* !WINDOWS && !MSDOS */
|
||||
|
||||
@@ -703,7 +706,7 @@ unique_create (const char *name, bool binary, char **opened_name)
|
||||
xfree (uname);
|
||||
uname = unique_name (name, false);
|
||||
}
|
||||
if (opened_name && fp != NULL)
|
||||
if (opened_name)
|
||||
{
|
||||
if (fp)
|
||||
*opened_name = uname;
|
||||
@@ -900,15 +903,14 @@ static bool in_acclist (const char *const *, const char *, bool);
|
||||
bool
|
||||
acceptable (const char *s)
|
||||
{
|
||||
int l = strlen (s);
|
||||
const char *p;
|
||||
|
||||
if (opt.output_document && strcmp (s, opt.output_document) == 0)
|
||||
return true;
|
||||
|
||||
while (l && s[l] != '/')
|
||||
--l;
|
||||
if (s[l] == '/')
|
||||
s += (l + 1);
|
||||
if ((p = strrchr (s, '/')))
|
||||
s = p + 1;
|
||||
|
||||
if (opt.accepts)
|
||||
{
|
||||
if (opt.rejects)
|
||||
@@ -919,6 +921,7 @@ acceptable (const char *s)
|
||||
}
|
||||
else if (opt.rejects)
|
||||
return !in_acclist ((const char *const *)opt.rejects, s, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -957,16 +960,16 @@ subdir_p (const char *d1, const char *d2)
|
||||
first element that matches DIR, through wildcards or front comparison (as
|
||||
appropriate). */
|
||||
static bool
|
||||
dir_matches_p (char **dirlist, const char *dir)
|
||||
dir_matches_p (const char **dirlist, const char *dir)
|
||||
{
|
||||
char **x;
|
||||
const char **x;
|
||||
int (*matcher) (const char *, const char *, int)
|
||||
= opt.ignore_case ? fnmatch_nocase : fnmatch;
|
||||
|
||||
for (x = dirlist; *x; x++)
|
||||
{
|
||||
/* Remove leading '/' */
|
||||
char *p = *x + (**x == '/');
|
||||
const char *p = *x + (**x == '/');
|
||||
if (has_wildcards_p (p))
|
||||
{
|
||||
if (matcher (p, dir, FNM_PATHNAME) == 0)
|
||||
@@ -1018,29 +1021,15 @@ accdir (const char *directory)
|
||||
bool
|
||||
match_tail (const char *string, const char *tail, bool fold_case)
|
||||
{
|
||||
int i, j;
|
||||
int pos = strlen (string) - strlen (tail);
|
||||
|
||||
/* We want this to be fast, so we code two loops, one with
|
||||
case-folding, one without. */
|
||||
if (pos < 0)
|
||||
return false; /* tail is longer than string. */
|
||||
|
||||
if (!fold_case)
|
||||
{
|
||||
for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)
|
||||
if (string[i] != tail[j])
|
||||
break;
|
||||
}
|
||||
return !strcmp (string + pos, tail);
|
||||
else
|
||||
{
|
||||
for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)
|
||||
if (c_tolower (string[i]) != c_tolower (tail[j]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the tail was exhausted, the match was succesful. */
|
||||
if (j == -1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return !strcasecmp (string + pos, tail);
|
||||
}
|
||||
|
||||
/* Checks whether string S matches each element of ACCEPTS. A list
|
||||
@@ -1089,15 +1078,12 @@ in_acclist (const char *const *accepts, const char *s, bool backward)
|
||||
char *
|
||||
suffix (const char *str)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
for (i = strlen (str); i && str[i] != '/' && str[i] != '.'; i--)
|
||||
;
|
||||
if ((p = strrchr (str, '.')) && !strchr (p + 1, '/'))
|
||||
return p + 1;
|
||||
|
||||
if (str[i++] == '.')
|
||||
return (char *)str + i;
|
||||
else
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return true if S contains globbing wildcards (`*', `?', `[' or
|
||||
@@ -1106,10 +1092,7 @@ suffix (const char *str)
|
||||
bool
|
||||
has_wildcards_p (const char *s)
|
||||
{
|
||||
for (; *s; s++)
|
||||
if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
|
||||
return true;
|
||||
return false;
|
||||
return !!strpbrk (s, "*?[]");
|
||||
}
|
||||
|
||||
/* Return true if FNAME ends with a typical HTML suffix. The
|
||||
@@ -1138,56 +1121,6 @@ has_html_suffix_p (const char *fname)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read a line from FP and return the pointer to freshly allocated
|
||||
storage. The storage space is obtained through malloc() and should
|
||||
be freed with free() when it is no longer needed.
|
||||
|
||||
The length of the line is not limited, except by available memory.
|
||||
The newline character at the end of line is retained. The line is
|
||||
terminated with a zero character.
|
||||
|
||||
After end-of-file is encountered without anything being read, NULL
|
||||
is returned. NULL is also returned on error. To distinguish
|
||||
between these two cases, use the stdio function ferror(). */
|
||||
|
||||
char *
|
||||
read_whole_line (FILE *fp)
|
||||
{
|
||||
int length = 0;
|
||||
int bufsize = 82;
|
||||
char *line = xmalloc (bufsize);
|
||||
|
||||
while (fgets (line + length, bufsize - length, fp))
|
||||
{
|
||||
length += strlen (line + length);
|
||||
if (length == 0)
|
||||
/* Possible for example when reading from a binary file where
|
||||
a line begins with \0. */
|
||||
continue;
|
||||
|
||||
if (line[length - 1] == '\n')
|
||||
break;
|
||||
|
||||
/* fgets() guarantees to read the whole line, or to use up the
|
||||
space we've given it. We can double the buffer
|
||||
unconditionally. */
|
||||
bufsize <<= 1;
|
||||
line = xrealloc (line, bufsize);
|
||||
}
|
||||
if (length == 0 || ferror (fp))
|
||||
{
|
||||
xfree (line);
|
||||
return NULL;
|
||||
}
|
||||
if (length + 1 < bufsize)
|
||||
/* Relieve the memory from our exponential greediness. We say
|
||||
`length + 1' because the terminating \0 is not included in
|
||||
LENGTH. We don't need to zero-terminate the string ourselves,
|
||||
though, because fgets() does that. */
|
||||
line = xrealloc (line, length + 1);
|
||||
return line;
|
||||
}
|
||||
|
||||
/* Read FILE into memory. A pointer to `struct file_memory' are
|
||||
returned; use struct element `content' to access file contents, and
|
||||
the element `length' to know the file length. `content' is *not*
|
||||
@@ -1590,7 +1523,7 @@ with_thousand_seps (wgint n)
|
||||
some detail. */
|
||||
|
||||
char *
|
||||
human_readable (HR_NUMTYPE n)
|
||||
human_readable (HR_NUMTYPE n, const int acc, const int decimals)
|
||||
{
|
||||
/* These suffixes are compatible with those of GNU `ls -lh'. */
|
||||
static char powers[] =
|
||||
@@ -1623,10 +1556,10 @@ human_readable (HR_NUMTYPE n)
|
||||
if ((n / 1024) < 1024 || i == countof (powers) - 1)
|
||||
{
|
||||
double val = n / 1024.0;
|
||||
/* Print values smaller than 10 with one decimal digits, and
|
||||
others without any decimals. */
|
||||
/* Print values smaller than the accuracy level (acc) with (decimal)
|
||||
* decimal digits, and others without any decimals. */
|
||||
snprintf (buf, sizeof (buf), "%.*f%c",
|
||||
val < 10 ? 1 : 0, val, powers[i]);
|
||||
val < acc ? decimals : 0, val, powers[i]);
|
||||
return buf;
|
||||
}
|
||||
n /= 1024;
|
||||
@@ -1963,7 +1896,7 @@ random_float (void)
|
||||
|
||||
static sigjmp_buf run_with_timeout_env;
|
||||
|
||||
static void
|
||||
static void _Noreturn
|
||||
abort_run_with_timeout (int sig)
|
||||
{
|
||||
assert (sig == SIGALRM);
|
||||
@@ -2078,6 +2011,16 @@ run_with_timeout (double timeout, void (*fun) (void *), void *arg)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_THREADS
|
||||
if (opt.jobs > 1)
|
||||
{
|
||||
/* XXX: FIXME. Support this functionality when there are
|
||||
multiple threads. Do not translate the string. */
|
||||
logputs (LOG_NOTQUIET, "\ntimeouts not (yet) supported with threads.\n");
|
||||
abort ();
|
||||
}
|
||||
#endif
|
||||
|
||||
signal (SIGALRM, abort_run_with_timeout);
|
||||
if (SETJMP (run_with_timeout_env) != 0)
|
||||
{
|
||||
@@ -2172,8 +2115,8 @@ xsleep (double seconds)
|
||||
This implementation does not emit newlines after 76 characters of
|
||||
base64 data. */
|
||||
|
||||
int
|
||||
base64_encode (const void *data, int length, char *dest)
|
||||
size_t
|
||||
base64_encode (const void *data, size_t length, char *dest)
|
||||
{
|
||||
/* Conversion table. */
|
||||
static const char tbl[64] = {
|
||||
@@ -2235,12 +2178,12 @@ base64_encode (const void *data, int length, char *dest)
|
||||
|
||||
Since DEST is assumed to contain binary data, it is not
|
||||
NUL-terminated. The function returns the length of the data
|
||||
written to TO. -1 is returned in case of error caused by malformed
|
||||
written to "TO". -1 is returned in case of error caused by malformed
|
||||
base64 input.
|
||||
|
||||
This function originates from Free Recode. */
|
||||
|
||||
int
|
||||
ssize_t
|
||||
base64_decode (const char *base64, void *dest)
|
||||
{
|
||||
/* Table of base64 values for first 128 characters. Note that this
|
||||
@@ -2353,7 +2296,7 @@ compile_posix_regex (const char *str)
|
||||
int errcode = regcomp ((regex_t *) regex, str, REG_EXTENDED | REG_NOSUB);
|
||||
if (errcode != 0)
|
||||
{
|
||||
int errbuf_size = regerror (errcode, (regex_t *) regex, NULL, 0);
|
||||
size_t errbuf_size = regerror (errcode, (regex_t *) regex, NULL, 0);
|
||||
char *errbuf = xmalloc (errbuf_size);
|
||||
regerror (errcode, (regex_t *) regex, errbuf, errbuf_size);
|
||||
fprintf (stderr, _("Invalid regular expression %s, %s\n"),
|
||||
@@ -2371,10 +2314,10 @@ compile_posix_regex (const char *str)
|
||||
bool
|
||||
match_pcre_regex (const void *regex, const char *str)
|
||||
{
|
||||
int l = strlen (str);
|
||||
size_t l = strlen (str);
|
||||
int ovector[OVECCOUNT];
|
||||
|
||||
int rc = pcre_exec ((pcre *) regex, 0, str, l, 0, 0, ovector, OVECCOUNT);
|
||||
int rc = pcre_exec ((pcre *) regex, 0, str, (int) l, 0, 0, ovector, OVECCOUNT);
|
||||
if (rc == PCRE_ERROR_NOMATCH)
|
||||
return false;
|
||||
else if (rc < 0)
|
||||
@@ -2400,7 +2343,7 @@ match_posix_regex (const void *regex, const char *str)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
int errbuf_size = regerror (rc, opt.acceptregex, NULL, 0);
|
||||
size_t errbuf_size = regerror (rc, opt.acceptregex, NULL, 0);
|
||||
char *errbuf = xmalloc (errbuf_size);
|
||||
regerror (rc, opt.acceptregex, errbuf, errbuf_size);
|
||||
logprintf (LOG_VERBOSE, _("Error while matching %s: %d\n"),
|
||||
@@ -2494,21 +2437,75 @@ print_decimal (double number)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Get the maximum name length for the given path. */
|
||||
/* Return 0 if length is unknown. */
|
||||
long
|
||||
get_max_length (const char *path, int length, int name)
|
||||
{
|
||||
long ret;
|
||||
char *p, *d;
|
||||
|
||||
/* Make a copy of the path that we can modify. */
|
||||
p = path ? strdupdelim (path, path + length) : strdup ("");
|
||||
|
||||
for (;;)
|
||||
{
|
||||
errno = 0;
|
||||
/* For an empty path query the current directory. */
|
||||
#if HAVE_PATHCONF
|
||||
ret = pathconf (*p ? p : ".", name);
|
||||
if (!(ret < 0 && errno == ENOENT))
|
||||
break;
|
||||
#else
|
||||
ret = PATH_MAX;
|
||||
#endif
|
||||
|
||||
/* The path does not exist yet, but may be created. */
|
||||
/* Already at current or root directory, give up. */
|
||||
if (!*p || strcmp (p, "/") == 0)
|
||||
break;
|
||||
|
||||
/* Remove one directory level and try again. */
|
||||
d = strrchr (p, '/');
|
||||
if (d == p)
|
||||
p[1] = '\0'; /* check root directory */
|
||||
else if (d)
|
||||
*d = '\0'; /* remove last directory part */
|
||||
else
|
||||
*p = '\0'; /* check current directory */
|
||||
}
|
||||
|
||||
xfree (p);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* pathconf() has a message for us. */
|
||||
if (errno != 0)
|
||||
perror ("pathconf");
|
||||
|
||||
/* If (errno == 0) then there is no max length.
|
||||
Even on error return 0 so the caller can continue. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
|
||||
const char *
|
||||
test_subdir_p()
|
||||
test_subdir_p(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *d1;
|
||||
char *d2;
|
||||
static const struct {
|
||||
const char *d1;
|
||||
const char *d2;
|
||||
bool result;
|
||||
} test_array[] = {
|
||||
{ "/somedir", "/somedir", true },
|
||||
{ "/somedir", "/somedir/d2", true },
|
||||
{ "/somedir/d1", "/somedir", false },
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
@@ -2522,12 +2519,11 @@ test_subdir_p()
|
||||
}
|
||||
|
||||
const char *
|
||||
test_dir_matches_p()
|
||||
test_dir_matches_p(void)
|
||||
{
|
||||
int i;
|
||||
struct {
|
||||
char *dirlist[3];
|
||||
char *dir;
|
||||
static struct {
|
||||
const char *dirlist[3];
|
||||
const char *dir;
|
||||
bool result;
|
||||
} test_array[] = {
|
||||
{ { "/somedir", "/someotherdir", NULL }, "somedir", true },
|
||||
@@ -2546,6 +2542,7 @@ test_dir_matches_p()
|
||||
{ { "/Tmp/has", NULL, NULL }, "/Tmp/has space", false },
|
||||
{ { "/Tmp/has", NULL, NULL }, "/Tmp/has,comma", false },
|
||||
};
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < countof(test_array); ++i)
|
||||
{
|
||||
@@ -2559,4 +2556,3 @@ test_dir_matches_p()
|
||||
}
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
|
||||
@@ -98,7 +98,6 @@ bool has_wildcards_p (const char *);
|
||||
|
||||
bool has_html_suffix_p (const char *);
|
||||
|
||||
char *read_whole_line (FILE *);
|
||||
struct file_memory *wget_read_file (const char *);
|
||||
void wget_read_file_free (struct file_memory *);
|
||||
|
||||
@@ -122,7 +121,7 @@ const char *with_thousand_seps (wgint);
|
||||
#else
|
||||
# define HR_NUMTYPE double
|
||||
#endif
|
||||
char *human_readable (HR_NUMTYPE);
|
||||
char *human_readable (HR_NUMTYPE, const int, const int);
|
||||
|
||||
|
||||
int numdigit (wgint);
|
||||
@@ -140,8 +139,8 @@ void xsleep (double);
|
||||
/* How many bytes it will take to store LEN bytes in base64. */
|
||||
#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
|
||||
|
||||
int base64_encode (const void *, int, char *);
|
||||
int base64_decode (const char *, void *);
|
||||
size_t base64_encode (const void *, size_t, char *);
|
||||
ssize_t base64_decode (const char *, void *);
|
||||
|
||||
#ifdef HAVE_LIBPCRE
|
||||
void *compile_pcre_regex (const char *);
|
||||
@@ -155,6 +154,8 @@ void stable_sort (void *, size_t, size_t, int (*) (const void *, const void *));
|
||||
|
||||
const char *print_decimal (double);
|
||||
|
||||
long get_max_length (const char *path, int length, int name);
|
||||
|
||||
extern unsigned char char_prop[];
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
||||
16
src/vms.c
16
src/vms.c
@@ -45,7 +45,7 @@
|
||||
*
|
||||
* Simplifies a fancy URL-derived file name into an ODS2- or
|
||||
* ODS5-compatible file name.
|
||||
*
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* utime()
|
||||
@@ -299,7 +299,7 @@ int dmy_lib$initialize = (int) lib$initialize;
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/* vms_arch()
|
||||
|
||||
|
||||
Returns (run-time) VMS architecture string.
|
||||
*/
|
||||
|
||||
@@ -556,12 +556,12 @@ char *vms_getpass( const char *prompt)
|
||||
fclose( sdc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/* vms_vers()
|
||||
|
||||
|
||||
Returns (run-time) VMS version string.
|
||||
*/
|
||||
|
||||
@@ -841,12 +841,11 @@ else
|
||||
|
||||
/* Action routine for decc$to_vms(), in utime(). */
|
||||
|
||||
char vms_path[ NAMX$C_MAXRSS+ 1];
|
||||
char *vms_path;
|
||||
|
||||
int set_vms_name( char *name, int type)
|
||||
{
|
||||
strncpy( vms_path, name, NAMX$C_MAXRSS);
|
||||
vms_path[ NAMX$C_MAXRSS] = '\0';
|
||||
vms_path = strdup(name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1337,7 +1336,7 @@ localtime_r (t, tp)
|
||||
return tp;
|
||||
}
|
||||
|
||||
#endif /* __CRTL_VER < 70000000 */
|
||||
#endif /* __CRTL_VER < 70000000 */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@@ -1350,4 +1349,3 @@ const char *link_string = NULL;
|
||||
const char *version_string = VERSION;
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
194
src/warc.c
194
src/warc.c
@@ -36,7 +36,6 @@ as that of the covered work. */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <tmpdir.h>
|
||||
#include <sha1.h>
|
||||
@@ -45,15 +44,25 @@ as that of the covered work. */
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUUID
|
||||
#include <uuid/uuid.h>
|
||||
#elif HAVE_UUID_CREATE
|
||||
#include <uuid.h>
|
||||
#endif
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <libgen.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "warc.h"
|
||||
#include "exits.h"
|
||||
|
||||
#ifndef O_TEMPORARY
|
||||
#define O_TEMPORARY 0
|
||||
#endif
|
||||
|
||||
extern char *version_string;
|
||||
|
||||
@@ -102,7 +111,7 @@ static char *warc_current_filename;
|
||||
static int warc_current_file_number;
|
||||
|
||||
/* The table of CDX records, if deduplication is enabled. */
|
||||
struct hash_table * warc_cdx_dedup_table;
|
||||
static struct hash_table * warc_cdx_dedup_table;
|
||||
|
||||
static bool warc_start_new_file (bool meta);
|
||||
|
||||
@@ -165,7 +174,7 @@ warc_write_string (const char *str)
|
||||
}
|
||||
|
||||
|
||||
#define EXTRA_GZIP_HEADER_SIZE 12
|
||||
#define EXTRA_GZIP_HEADER_SIZE 14
|
||||
#define GZIP_STATIC_HEADER_SIZE 10
|
||||
#define FLG_FEXTRA 0x04
|
||||
#define OFF_FLG 3
|
||||
@@ -200,7 +209,7 @@ warc_write_start_record (void)
|
||||
In warc_write_end_record we will fill this space
|
||||
with information about the uncompressed and
|
||||
compressed size of the record. */
|
||||
fprintf (warc_current_file, "XXXXXXXXXXXX");
|
||||
fseek (warc_current_file, EXTRA_GZIP_HEADER_SIZE, SEEK_CUR);
|
||||
fflush (warc_current_file);
|
||||
|
||||
/* Start a new GZIP stream. */
|
||||
@@ -245,15 +254,10 @@ static bool
|
||||
warc_write_block_from_file (FILE *data_in)
|
||||
{
|
||||
/* Add the Content-Length header. */
|
||||
char *content_length;
|
||||
char content_length[MAX_INT_TO_STRING_LEN(off_t)];
|
||||
fseeko (data_in, 0L, SEEK_END);
|
||||
if (! asprintf (&content_length, "%ld", ftello (data_in)))
|
||||
{
|
||||
warc_write_ok = false;
|
||||
return false;
|
||||
}
|
||||
number_to_string (content_length, ftello (data_in));
|
||||
warc_write_header ("Content-Length", content_length);
|
||||
free (content_length);
|
||||
|
||||
/* End of the WARC header section. */
|
||||
warc_write_string ("\r\n");
|
||||
@@ -347,16 +351,19 @@ warc_write_end_record (void)
|
||||
/* The extra header field identifier for the WARC skip length. */
|
||||
extra_header[2] = 's';
|
||||
extra_header[3] = 'l';
|
||||
/* The size of the field value (8 bytes). */
|
||||
extra_header[4] = (8 & 255);
|
||||
extra_header[5] = ((8 >> 8) & 255);
|
||||
/* The size of the uncompressed record. */
|
||||
extra_header[4] = (uncompressed_size & 255);
|
||||
extra_header[5] = (uncompressed_size >> 8) & 255;
|
||||
extra_header[6] = (uncompressed_size >> 16) & 255;
|
||||
extra_header[7] = (uncompressed_size >> 24) & 255;
|
||||
extra_header[6] = (uncompressed_size & 255);
|
||||
extra_header[7] = (uncompressed_size >> 8) & 255;
|
||||
extra_header[8] = (uncompressed_size >> 16) & 255;
|
||||
extra_header[9] = (uncompressed_size >> 24) & 255;
|
||||
/* The size of the compressed record. */
|
||||
extra_header[8] = (compressed_size & 255);
|
||||
extra_header[9] = (compressed_size >> 8) & 255;
|
||||
extra_header[10] = (compressed_size >> 16) & 255;
|
||||
extra_header[11] = (compressed_size >> 24) & 255;
|
||||
extra_header[10] = (compressed_size & 255);
|
||||
extra_header[11] = (compressed_size >> 8) & 255;
|
||||
extra_header[12] = (compressed_size >> 16) & 255;
|
||||
extra_header[13] = (compressed_size >> 24) & 255;
|
||||
|
||||
/* Write the extra header after the static header. */
|
||||
fseeko (warc_current_file, warc_current_gzfile_offset
|
||||
@@ -379,9 +386,9 @@ warc_write_end_record (void)
|
||||
static bool
|
||||
warc_write_date_header (const char *timestamp)
|
||||
{
|
||||
char current_timestamp[21];
|
||||
if (timestamp == NULL)
|
||||
{
|
||||
char current_timestamp[21];
|
||||
warc_timestamp (current_timestamp);
|
||||
timestamp = current_timestamp;
|
||||
}
|
||||
@@ -532,7 +539,7 @@ warc_sha1_stream_with_payload (FILE *stream, void *res_block, void *res_payload,
|
||||
static char *
|
||||
warc_base32_sha1_digest (char *sha1_digest)
|
||||
{
|
||||
// length: "sha1:" + digest + "\0"
|
||||
/* length: "sha1:" + digest + "\0" */
|
||||
char *sha1_base32 = malloc (BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1 + 5 );
|
||||
base32_encode (sha1_digest, SHA1_DIGEST_SIZE, sha1_base32 + 5,
|
||||
BASE32_LENGTH(SHA1_DIGEST_SIZE) + 1);
|
||||
@@ -590,7 +597,7 @@ warc_timestamp (char *timestamp)
|
||||
strftime (timestamp, 21, "%Y-%m-%dT%H:%M:%SZ", timeinfo);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBUUID
|
||||
#if HAVE_LIBUUID || HAVE_UUID_CREATE
|
||||
/* Fills urn_str with a UUID in the format required
|
||||
for the WARC-Record-Id header.
|
||||
The string will be 47 characters long. */
|
||||
@@ -600,8 +607,13 @@ warc_uuid_str (char *urn_str)
|
||||
char uuid_str[37];
|
||||
|
||||
uuid_t record_id;
|
||||
#if HAVE_UUID_CREATE
|
||||
uuid_create (&record_id, NULL);
|
||||
uuid_to_string (&record_id, &uuid_str, NULL);
|
||||
#else
|
||||
uuid_generate (record_id);
|
||||
uuid_unparse (record_id, uuid_str);
|
||||
#endif
|
||||
|
||||
sprintf (urn_str, "<urn:uuid:%s>", uuid_str);
|
||||
}
|
||||
@@ -722,10 +734,9 @@ warc_start_new_file (bool meta)
|
||||
|
||||
if (warc_current_file != NULL)
|
||||
fclose (warc_current_file);
|
||||
if (warc_current_warcinfo_uuid_str)
|
||||
free (warc_current_warcinfo_uuid_str);
|
||||
if (warc_current_filename)
|
||||
free (warc_current_filename);
|
||||
|
||||
free (warc_current_warcinfo_uuid_str);
|
||||
free (warc_current_filename);
|
||||
|
||||
warc_current_file_number++;
|
||||
|
||||
@@ -734,8 +745,14 @@ warc_start_new_file (bool meta)
|
||||
char *new_filename = malloc (base_filename_length + 1 + 5 + 8 + 1);
|
||||
warc_current_filename = new_filename;
|
||||
|
||||
#ifdef __VMS
|
||||
# define WARC_GZ "warc-gz"
|
||||
#else /* def __VMS */
|
||||
# define WARC_GZ "warc.gz"
|
||||
#endif /* def __VMS [else] */
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
const char *extension = (opt.warc_compression_enabled ? "warc.gz" : "warc");
|
||||
const char *extension = (opt.warc_compression_enabled ? WARC_GZ : "warc");
|
||||
#else
|
||||
const char *extension = "warc";
|
||||
#endif
|
||||
@@ -908,8 +925,7 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
|
||||
else
|
||||
{
|
||||
free (original_url);
|
||||
if (checksum_v != NULL)
|
||||
free (checksum_v);
|
||||
free (checksum_v);
|
||||
free (record_id);
|
||||
}
|
||||
}
|
||||
@@ -1005,12 +1021,10 @@ warc_find_duplicate_cdx_record (char *url, char *sha1_digest_payload)
|
||||
if (warc_cdx_dedup_table == NULL)
|
||||
return NULL;
|
||||
|
||||
char *key;
|
||||
struct warc_cdx_record *rec_existing;
|
||||
int found = hash_table_get_pair (warc_cdx_dedup_table, sha1_digest_payload,
|
||||
&key, &rec_existing);
|
||||
struct warc_cdx_record *rec_existing
|
||||
= hash_table_get (warc_cdx_dedup_table, sha1_digest_payload);
|
||||
|
||||
if (found && strcmp (rec_existing->url, url) == 0)
|
||||
if (rec_existing && strcmp (rec_existing->url, url) == 0)
|
||||
return rec_existing;
|
||||
else
|
||||
return NULL;
|
||||
@@ -1032,7 +1046,7 @@ warc_init (void)
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Could not read CDX file %s for deduplication.\n"),
|
||||
quote (opt.warc_cdx_dedup_filename));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,7 +1055,7 @@ warc_init (void)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Could not open temporary WARC manifest file.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
if (opt.warc_keep_log)
|
||||
@@ -1051,7 +1065,7 @@ warc_init (void)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Could not open temporary WARC log file.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
log_set_warc_log_fp (warc_log_fp);
|
||||
}
|
||||
@@ -1060,7 +1074,7 @@ warc_init (void)
|
||||
if (! warc_start_new_file (false))
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("Could not open WARC file.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
|
||||
if (opt.warc_cdx_enabled)
|
||||
@@ -1069,7 +1083,7 @@ warc_init (void)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Could not open CDX file for output.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1101,7 @@ warc_write_metadata (void)
|
||||
warc_uuid_str (manifest_uuid);
|
||||
|
||||
fflush (warc_manifest_fp);
|
||||
warc_write_resource_record (manifest_uuid,
|
||||
warc_write_metadata_record (manifest_uuid,
|
||||
"metadata://gnu.org/software/wget/warc/MANIFEST.txt",
|
||||
NULL, NULL, NULL, "text/plain",
|
||||
warc_manifest_fp, -1);
|
||||
@@ -1097,14 +1111,14 @@ warc_write_metadata (void)
|
||||
if (warc_tmp_fp == NULL)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("Could not open temporary WARC file.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
fflush (warc_tmp_fp);
|
||||
fprintf (warc_tmp_fp, "%s\n", program_argstring);
|
||||
|
||||
warc_write_resource_record (manifest_uuid,
|
||||
warc_write_resource_record (NULL,
|
||||
"metadata://gnu.org/software/wget/warc/wget_arguments.txt",
|
||||
NULL, NULL, NULL, "text/plain",
|
||||
NULL, manifest_uuid, NULL, "text/plain",
|
||||
warc_tmp_fp, -1);
|
||||
/* warc_write_resource_record has closed warc_tmp_fp. */
|
||||
|
||||
@@ -1151,14 +1165,32 @@ warc_tempfile (void)
|
||||
if (path_search (filename, 100, opt.warc_tempdir, "wget", true) == -1)
|
||||
return NULL;
|
||||
|
||||
int fd = mkstemp (filename);
|
||||
#ifdef __VMS
|
||||
/* 2013-07-12 SMS.
|
||||
* mkostemp()+unlink()+fdopen() scheme causes trouble on VMS, so use
|
||||
* mktemp() to uniquify the (VMS-style) name, and then use a normal
|
||||
* fopen() with a "create temp file marked for delete" option.
|
||||
*/
|
||||
{
|
||||
char *tfn;
|
||||
|
||||
tfn = mktemp (filename); /* Get unique name from template. */
|
||||
if (tfn == NULL)
|
||||
return NULL;
|
||||
return fopen (tfn, "w+", "fop=tmd"); /* Create auto-delete temp file. */
|
||||
}
|
||||
#else /* def __VMS */
|
||||
int fd = mkostemp (filename, O_TEMPORARY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
#if !O_TEMPORARY
|
||||
if (unlink (filename) < 0)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
return fdopen (fd, "wb+");
|
||||
#endif /* def __VMS [else] */
|
||||
}
|
||||
|
||||
|
||||
@@ -1207,7 +1239,7 @@ static bool
|
||||
warc_write_cdx_record (const char *url, const char *timestamp_str,
|
||||
const char *mime_type, int response_code,
|
||||
const char *payload_digest, const char *redirect_location,
|
||||
off_t offset, const char *warc_filename,
|
||||
off_t offset, const char *warc_filename _GL_UNUSED,
|
||||
const char *response_uuid)
|
||||
{
|
||||
/* Transform the timestamp. */
|
||||
@@ -1232,10 +1264,14 @@ warc_write_cdx_record (const char *url, const char *timestamp_str,
|
||||
if (redirect_location == NULL || strlen(redirect_location) == 0)
|
||||
redirect_location = "-";
|
||||
|
||||
char offset_string[MAX_INT_TO_STRING_LEN(off_t)];
|
||||
number_to_string (offset_string, offset);
|
||||
|
||||
/* Print the CDX line. */
|
||||
fprintf (warc_current_cdx_file, "%s %s %s %s %d %s %s - %ld %s %s\n", url,
|
||||
fprintf (warc_current_cdx_file, "%s %s %s %s %d %s %s - %s %s %s\n", url,
|
||||
timestamp_str_cdx, url, mime_type, response_code, checksum,
|
||||
redirect_location, offset, warc_current_filename, response_uuid);
|
||||
redirect_location, offset_string, warc_current_filename,
|
||||
response_uuid);
|
||||
fflush (warc_current_cdx_file);
|
||||
|
||||
return true;
|
||||
@@ -1387,28 +1423,28 @@ warc_write_response_record (char *url, char *timestamp_str,
|
||||
response_uuid);
|
||||
}
|
||||
|
||||
if (block_digest)
|
||||
free (block_digest);
|
||||
if (payload_digest)
|
||||
free (payload_digest);
|
||||
free (block_digest);
|
||||
free (payload_digest);
|
||||
|
||||
return warc_write_ok;
|
||||
}
|
||||
|
||||
/* Writes a resource record to the WARC file.
|
||||
/* Writes a resource or metadata record to the WARC file.
|
||||
warc_type is either "resource" or "metadata",
|
||||
resource_uuid is the uuid of the resource (or NULL),
|
||||
url is the target uri of the resource,
|
||||
timestamp_str is the timestamp (generated with warc_timestamp),
|
||||
concurrent_to_uuid is the uuid of the request for that generated this
|
||||
concurrent_to_uuid is the uuid of the record that generated this,
|
||||
resource (generated with warc_uuid_str) or NULL,
|
||||
ip is the ip address of the server (or NULL),
|
||||
content_type is the mime type of the body (or NULL),
|
||||
body is a pointer to a file containing the resource data.
|
||||
Calling this function will close body.
|
||||
Returns true on success, false on error. */
|
||||
bool
|
||||
warc_write_resource_record (char *resource_uuid, const char *url,
|
||||
const char *timestamp_str, const char *concurrent_to_uuid,
|
||||
static bool
|
||||
warc_write_record (const char *record_type, char *resource_uuid,
|
||||
const char *url, const char *timestamp_str,
|
||||
const char *concurrent_to_uuid,
|
||||
ip_address *ip, const char *content_type, FILE *body,
|
||||
off_t payload_offset)
|
||||
{
|
||||
@@ -1422,7 +1458,7 @@ warc_write_resource_record (char *resource_uuid, const char *url,
|
||||
content_type = "application/octet-stream";
|
||||
|
||||
warc_write_start_record ();
|
||||
warc_write_header ("WARC-Type", "resource");
|
||||
warc_write_header ("WARC-Type", record_type);
|
||||
warc_write_header ("WARC-Record-ID", resource_uuid);
|
||||
warc_write_header ("WARC-Warcinfo-ID", warc_current_warcinfo_uuid_str);
|
||||
warc_write_header ("WARC-Concurrent-To", concurrent_to_uuid);
|
||||
@@ -1438,3 +1474,47 @@ warc_write_resource_record (char *resource_uuid, const char *url,
|
||||
|
||||
return warc_write_ok;
|
||||
}
|
||||
|
||||
/* Writes a resource record to the WARC file.
|
||||
resource_uuid is the uuid of the resource (or NULL),
|
||||
url is the target uri of the resource,
|
||||
timestamp_str is the timestamp (generated with warc_timestamp),
|
||||
concurrent_to_uuid is the uuid of the record that generated this,
|
||||
resource (generated with warc_uuid_str) or NULL,
|
||||
ip is the ip address of the server (or NULL),
|
||||
content_type is the mime type of the body (or NULL),
|
||||
body is a pointer to a file containing the resource data.
|
||||
Calling this function will close body.
|
||||
Returns true on success, false on error. */
|
||||
bool
|
||||
warc_write_resource_record (char *resource_uuid, const char *url,
|
||||
const char *timestamp_str, const char *concurrent_to_uuid,
|
||||
ip_address *ip, const char *content_type, FILE *body,
|
||||
off_t payload_offset)
|
||||
{
|
||||
return warc_write_record ("resource",
|
||||
resource_uuid, url, timestamp_str, concurrent_to_uuid,
|
||||
ip, content_type, body, payload_offset);
|
||||
}
|
||||
|
||||
/* Writes a metadata record to the WARC file.
|
||||
record_uuid is the uuid of the record (or NULL),
|
||||
url is the target uri of the record,
|
||||
timestamp_str is the timestamp (generated with warc_timestamp),
|
||||
concurrent_to_uuid is the uuid of the record that generated this,
|
||||
record (generated with warc_uuid_str) or NULL,
|
||||
ip is the ip address of the server (or NULL),
|
||||
content_type is the mime type of the body (or NULL),
|
||||
body is a pointer to a file containing the record data.
|
||||
Calling this function will close body.
|
||||
Returns true on success, false on error. */
|
||||
bool
|
||||
warc_write_metadata_record (char *record_uuid, const char *url,
|
||||
const char *timestamp_str, const char *concurrent_to_uuid,
|
||||
ip_address *ip, const char *content_type, FILE *body,
|
||||
off_t payload_offset)
|
||||
{
|
||||
return warc_write_record ("metadata",
|
||||
record_uuid, url, timestamp_str, concurrent_to_uuid,
|
||||
ip, content_type, body, payload_offset);
|
||||
}
|
||||
|
||||
@@ -19,5 +19,8 @@ bool warc_write_response_record (char *url, char *timestamp_str,
|
||||
bool warc_write_resource_record (char *resource_uuid, const char *url,
|
||||
const char *timestamp_str, const char *concurrent_to_uuid, ip_address *ip,
|
||||
const char *content_type, FILE *body, off_t payload_offset);
|
||||
bool warc_write_metadata_record (char *record_uuid, const char *url,
|
||||
const char *timestamp_str, const char *concurrent_to_uuid, ip_address *ip,
|
||||
const char *content_type, FILE *body, off_t payload_offset);
|
||||
|
||||
#endif /* WARC_H */
|
||||
|
||||
112
src/wget.h
112
src/wget.h
@@ -72,12 +72,6 @@ as that of the covered work. */
|
||||
variables. -- explanation partly taken from GNU make. */
|
||||
#define N_(string) string
|
||||
|
||||
#if ! ENABLE_NLS
|
||||
# undef HAVE_WCHAR_H
|
||||
# undef HAVE_WCWIDTH
|
||||
# undef HAVE_MBTOWC
|
||||
#endif /* not ENABLE_NLS */
|
||||
|
||||
#if HAVE_WCWIDTH && HAVE_MBTOWC
|
||||
# define USE_NLS_PROGRESS_BAR 1
|
||||
#else
|
||||
@@ -254,24 +248,24 @@ typedef double SUM_SIZE_INT;
|
||||
/* Copy the data delimited with BEG and END to alloca-allocated
|
||||
storage, and zero-terminate it. Arguments are evaluated only once,
|
||||
in the order BEG, END, PLACE. */
|
||||
#define BOUNDED_TO_ALLOCA(beg, end, place) do { \
|
||||
const char *BTA_beg = (beg); \
|
||||
int BTA_len = (end) - BTA_beg; \
|
||||
char **BTA_dest = &(place); \
|
||||
*BTA_dest = alloca (BTA_len + 1); \
|
||||
memcpy (*BTA_dest, BTA_beg, BTA_len); \
|
||||
(*BTA_dest)[BTA_len] = '\0'; \
|
||||
#define BOUNDED_TO_ALLOCA(beg, end, place) do { \
|
||||
const char *BTA_beg = (beg); \
|
||||
int BTA_len = (end) - BTA_beg; \
|
||||
char **BTA_dest = &(place); \
|
||||
*BTA_dest = alloca (BTA_len + 1); \
|
||||
memcpy (*BTA_dest, BTA_beg, BTA_len); \
|
||||
(*BTA_dest)[BTA_len] = '\0'; \
|
||||
} while (0)
|
||||
|
||||
/* Return non-zero if string bounded between BEG and END is equal to
|
||||
STRING_LITERAL. The comparison is case-sensitive. */
|
||||
#define BOUNDED_EQUAL(beg, end, string_literal) \
|
||||
((end) - (beg) == sizeof (string_literal) - 1 \
|
||||
#define BOUNDED_EQUAL(beg, end, string_literal) \
|
||||
((end) - (beg) == sizeof (string_literal) - 1 \
|
||||
&& !memcmp (beg, string_literal, sizeof (string_literal) - 1))
|
||||
|
||||
/* The same as above, except the comparison is case-insensitive. */
|
||||
#define BOUNDED_EQUAL_NO_CASE(beg, end, string_literal) \
|
||||
((end) - (beg) == sizeof (string_literal) - 1 \
|
||||
#define BOUNDED_EQUAL_NO_CASE(beg, end, string_literal) \
|
||||
((end) - (beg) == sizeof (string_literal) - 1 \
|
||||
&& !strncasecmp (beg, string_literal, sizeof (string_literal) - 1))
|
||||
|
||||
/* Like ptr=strdup(str), but allocates the space for PTR on the stack.
|
||||
@@ -280,11 +274,11 @@ typedef double SUM_SIZE_INT;
|
||||
The problem is that some compilers can't handle alloca() being an
|
||||
argument to a function. */
|
||||
|
||||
#define STRDUP_ALLOCA(ptr, str) do { \
|
||||
char **SA_dest = &(ptr); \
|
||||
const char *SA_src = (str); \
|
||||
*SA_dest = (char *)alloca (strlen (SA_src) + 1); \
|
||||
strcpy (*SA_dest, SA_src); \
|
||||
#define STRDUP_ALLOCA(ptr, str) do { \
|
||||
char **SA_dest = &(ptr); \
|
||||
const char *SA_src = (str); \
|
||||
*SA_dest = (char *)alloca (strlen (SA_src) + 1); \
|
||||
strcpy (*SA_dest, SA_src); \
|
||||
} while (0)
|
||||
|
||||
/* Generally useful if you want to avoid arbitrary size limits but
|
||||
@@ -295,17 +289,17 @@ typedef double SUM_SIZE_INT;
|
||||
NEEDED_SIZE objects. The reallocing is done by doubling, which
|
||||
ensures constant amortized time per element. */
|
||||
|
||||
#define DO_REALLOC(basevar, sizevar, needed_size, type) do { \
|
||||
long DR_needed_size = (needed_size); \
|
||||
long DR_newsize = 0; \
|
||||
while ((sizevar) < (DR_needed_size)) { \
|
||||
DR_newsize = sizevar << 1; \
|
||||
if (DR_newsize < 16) \
|
||||
DR_newsize = 16; \
|
||||
(sizevar) = DR_newsize; \
|
||||
} \
|
||||
if (DR_newsize) \
|
||||
basevar = xrealloc (basevar, DR_newsize * sizeof (type)); \
|
||||
#define DO_REALLOC(basevar, sizevar, needed_size, type) do { \
|
||||
long DR_needed_size = (needed_size); \
|
||||
long DR_newsize = 0; \
|
||||
while ((sizevar) < (DR_needed_size)) { \
|
||||
DR_newsize = sizevar << 1; \
|
||||
if (DR_newsize < 16) \
|
||||
DR_newsize = 16; \
|
||||
(sizevar) = DR_newsize; \
|
||||
} \
|
||||
if (DR_newsize) \
|
||||
basevar = xrealloc (basevar, DR_newsize * sizeof (type)); \
|
||||
} while (0)
|
||||
|
||||
/* Used to print pointers (usually for debugging). Print pointers
|
||||
@@ -314,19 +308,23 @@ typedef double SUM_SIZE_INT;
|
||||
0-pad the address.) */
|
||||
#define PTR_FORMAT(p) (int) (2 * sizeof (void *)), (unsigned long) (p)
|
||||
|
||||
/* Find the maximum buffer length needed to print an integer of type `x'
|
||||
in base 10. 24082 / 10000 = 8*log_{10}(2). */
|
||||
#define MAX_INT_TO_STRING_LEN(x) ((sizeof(x) * 24082 / 10000) + 2)
|
||||
|
||||
extern const char *exec_name;
|
||||
|
||||
/* Document type ("dt") flags */
|
||||
enum
|
||||
{
|
||||
TEXTHTML = 0x0001, /* document is of type text/html
|
||||
TEXTHTML = 0x0001, /* document is of type text/html
|
||||
or application/xhtml+xml */
|
||||
RETROKF = 0x0002, /* retrieval was OK */
|
||||
HEAD_ONLY = 0x0004, /* only send the HEAD request */
|
||||
SEND_NOCACHE = 0x0008, /* send Pragma: no-cache directive */
|
||||
ACCEPTRANGES = 0x0010, /* Accept-ranges header was found */
|
||||
RETROKF = 0x0002, /* retrieval was OK */
|
||||
HEAD_ONLY = 0x0004, /* only send the HEAD request */
|
||||
SEND_NOCACHE = 0x0008, /* send Pragma: no-cache directive */
|
||||
ACCEPTRANGES = 0x0010, /* Accept-ranges header was found */
|
||||
ADDED_HTML_EXTENSION = 0x0020, /* added ".html" extension due to -E */
|
||||
TEXTCSS = 0x0040 /* document is of type text/css */
|
||||
TEXTCSS = 0x0040 /* document is of type text/css */
|
||||
};
|
||||
|
||||
/* Universal error type -- used almost everywhere. Error reporting of
|
||||
@@ -334,35 +332,35 @@ enum
|
||||
simplified. */
|
||||
typedef enum
|
||||
{
|
||||
/* 0 */
|
||||
NOCONERROR, HOSTERR, CONSOCKERR, CONERROR, CONSSLERR,
|
||||
CONIMPOSSIBLE, NEWLOCATION, NOTENOUGHMEM /* ! */,
|
||||
CONPORTERR /* ! */, CONCLOSED /* ! */,
|
||||
/* 10 */
|
||||
CONIMPOSSIBLE, NEWLOCATION,
|
||||
FTPOK, FTPLOGINC, FTPLOGREFUSED, FTPPORTERR, FTPSYSERR,
|
||||
FTPNSFOD, FTPRETROK /* ! */, FTPUNKNOWNTYPE, FTPRERR, FTPREXC /* ! */,
|
||||
/* 20 */
|
||||
FTPNSFOD, FTPUNKNOWNTYPE, FTPRERR,
|
||||
FTPSRVERR, FTPRETRINT, FTPRESTFAIL, URLERROR, FOPENERR,
|
||||
FOPEN_EXCL_ERR, FWRITEERR, HOK /* ! */, HLEXC /* ! */, HEOF,
|
||||
/* 30 */
|
||||
HERR, RETROK, RECLEVELEXC, FTPACCDENIED /* ! */, WRONGCODE,
|
||||
FOPEN_EXCL_ERR, FWRITEERR, HEOF,
|
||||
HERR, RETROK, RECLEVELEXC, WRONGCODE,
|
||||
FTPINVPASV, FTPNOPASV, CONTNOTSUPPORTED, RETRUNNEEDED, RETRFINISHED,
|
||||
/* 40 */
|
||||
READERR, TRYLIMEXC, URLBADPATTERN /* ! */, FILEBADFILE /* ! */, RANGEERR,
|
||||
RETRBADPATTERN, RETNOTSUP /* ! */, ROBOTSOK /* ! */, NOROBOTS /* ! */,
|
||||
PROXERR,
|
||||
/* 50 */
|
||||
READERR, TRYLIMEXC, FILEBADFILE, RANGEERR,
|
||||
RETRBADPATTERN, PROXERR,
|
||||
AUTHFAILED, QUOTEXC, WRITEFAILED, SSLINITFAILED, VERIFCERTERR,
|
||||
UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED,
|
||||
|
||||
WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR
|
||||
UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED, ATTRMISSING, UNKNOWNATTR,
|
||||
WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR, THREADS_ERR, SEM_ERR
|
||||
} uerr_t;
|
||||
|
||||
struct range {
|
||||
wgint first_byte;
|
||||
wgint last_byte;
|
||||
wgint bytes_covered;
|
||||
wgint is_assigned;
|
||||
bool *resources;
|
||||
uerr_t status_least_severe;
|
||||
};
|
||||
|
||||
/* 2005-02-19 SMS.
|
||||
Select an appropriate "orig" suffix and a separator character for
|
||||
adding a unique suffix to a file name.
|
||||
|
||||
A VMS ODS2 file system can not tolerate multiple dots. An ODS5 file
|
||||
A VMS ODS2 file system can't tolerate multiple dots. An ODS5 file
|
||||
system can, but even there not all dots are equal, and heroic effort
|
||||
would be needed to get ".html^.orig" rather than (the less desirable)
|
||||
"^.html.orig". It's more satisfactory always to use "_orig" on VMS
|
||||
|
||||
958
testenv/ChangeLog
Normal file
958
testenv/ChangeLog
Normal file
@@ -0,0 +1,958 @@
|
||||
2014-07-23 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* test/base_test.py (BaseTest.gen_cmd_line): Add support for running all
|
||||
tests through valgrind if the relevant environment variable is set
|
||||
* conf/expected_ret_code (ExpectedRetCode.__call__): Valgrind returns error
|
||||
code 45 when it detects a memory leak.
|
||||
* Readme: Update with details about valgrind tests
|
||||
|
||||
2014-07-22 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* (README): Remove old TODO and document SERVER_WAIT variable
|
||||
|
||||
2014-06-22 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* (conf.files_crawled): diff is a set object and needs explicit str
|
||||
conversion.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* base_test.py:
|
||||
(CommonMethods): Rename to BaseTest.
|
||||
(BaseTest): Implement __init__ method where the class-wide variables are
|
||||
initialized. Also variable names like `xxx_list` is renamed to its plural
|
||||
form, e.g. `server_list` => `servers`.
|
||||
(BaseTest.init_test_env): Remove name argument due to its unnecessarity.
|
||||
(BaseTest.get_test_dir): Because the path of the test directory is needed
|
||||
in multiple methods, this method is implemented.
|
||||
(BaseTest.get_domain_addr): Rewrite the return statement utilizing str
|
||||
formatting (which is more Pythonic).
|
||||
(BaseTest.get_cmd_line): Rename to gen_cmd_line. Change the variables with
|
||||
capitcal characters to lower ones. Also, the nested for loop is rewritten
|
||||
to a plain loop using the zip function.
|
||||
(BaseTest.__gen_local_filesys): Rename to gen_local_fs_snapshot. Move to
|
||||
ExpectedFiles in conf/expected_files.py and is marked as a static
|
||||
method. Refactor to a less verbose implementation.
|
||||
(BaseTest._check_downloaded_files): Rename to __call__ to agree with the
|
||||
invocation in test case classes. Move to ExpectedFiles in
|
||||
conf/expected_files.py.
|
||||
(BaseTest.get_server_rules): Refactor to a more Pythonic form utilizing
|
||||
dict.items() and is marked static.
|
||||
(BaseTest.stop_server): (new method) an abstract method which should stop
|
||||
the currently using servers.
|
||||
(BaseTest.instantiate_server_by): (new method) an abstract method which
|
||||
should instantiate a server instance according to the given argument.
|
||||
(BaseTest.__enter__): (new method) method which initialize the context
|
||||
manager
|
||||
(BaseTest.__exit__): (new method) method that finilize the context manager
|
||||
and deal with the exceptions during the execution of the with statement,
|
||||
subclasses can override this method for extensibility
|
||||
* http_test.py:
|
||||
(HTTPTest.__init__): Add call to super.__init__. Default values of
|
||||
pre_hook, test_params, post_hook are set to None to avoid a subtle bug of
|
||||
Python. Argument servers is renamed to protocols.
|
||||
(HTTPTest.Server_setup): Move to BaseTest and rename to server_setup.
|
||||
Calls to pre_hook_call, call_test, post_hook_call are removed.
|
||||
(HTTPTest.hook_call, pre_hook_call, call_test, post_hook_call): Move to
|
||||
BaseTest for that both HTTP test cases and FTP test cases may use these
|
||||
methods.
|
||||
(HTTPTest.init_HTTP_Server, init_HTTPS_Server): Merge and rename to
|
||||
instantiate_server_by to implement the abstract method in BaseTest.
|
||||
(HTTPTest.stop_HTTP_Server): Rename to stop_server to implement the
|
||||
abstract method in BaseTest. Also, pull out the part where remaining
|
||||
requests are gathered into a new method request_remaining.
|
||||
(BaseTest.act_retcode): Rename to ret_code because ExpectedRetCode is
|
||||
moved out from BaseTest, so the name act_retcode is actually a bit
|
||||
verbose.
|
||||
* conf/expected_ret_code.py:
|
||||
(ExpectedRetCode.__call__): Rewrite the str into a more readable form.
|
||||
* conf/files_crawled.py:
|
||||
(FilesCrawled.__call__): Refactor this method into a more Pythonic form
|
||||
utilizing the zip function.
|
||||
* conf/local_files.py:
|
||||
(LocalFiles__call__): Rewrite this method with the recommended with
|
||||
statement.
|
||||
* conf/server_conf.py:
|
||||
(ServerConf.__call__): Rewrite this method due to BaseTest.server_list is
|
||||
renamed to BaseTest.servers.
|
||||
* conf/server_files.py:
|
||||
(ServerFiles.__call__): Refactor the nested for loop into a plain one
|
||||
utilizing the zip function.
|
||||
* conf/urls.py:
|
||||
(URLs): Rename url_list to urls.
|
||||
* conf/wget_commands.py:
|
||||
(WgetCommands): Rename command_list to commands, rename test_obj.options
|
||||
to test_obj.wget_options.
|
||||
* Test--https.py, Test-Proto.py, Test-Parallel-Proto.py: Argument servers
|
||||
is changed to protocols due to change in the signature of
|
||||
HTTPTest.__init__.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* test: (new package) package for test case classes
|
||||
* WgetTest.py: Split into test/base_test.py and test/http_test.py.
|
||||
* Test-*.py: Optimize the imports according to changes of WgetTest.py
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* server: (new package) package for the server classes
|
||||
* server.http: (new package) package for HTTP server
|
||||
* server.ftp: (new package) package for FTP server
|
||||
* HTTPServer.py: Move to server/http/http_server.py. Also change the
|
||||
CERTFILE to '../certs/wget-cert.pem'.
|
||||
* FTPServer.py: Move to server/ftp/ftp_server.py.
|
||||
* WgetTest.py: Optimize import respect to the server classes.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* conf: (new package) package for rule classes and hook methods
|
||||
* WgetTest.py:
|
||||
(CommonMethods.Authentication): Move to conf/authentication.py.
|
||||
(CommonMethods.ExpectHeader): Move to conf/expect_header.py.
|
||||
(CommonMethods.RejectHeader): Move to conf/reject_header.py.
|
||||
(CommonMethods.Response): Move to conf/response.py.
|
||||
(CommonMethods.SendHeader): Move to conf/send_header.py.
|
||||
(CommonMethods.ServerFiles): Move to conf/server_files.py.
|
||||
(CommonMethods.LocalFiles): Move to conf/local_files.py.
|
||||
(CommonMethods.ServerConf): Move to conf/server_conf.py.
|
||||
(CommonMethods.WgetCommands): Move to conf/wget_commands.py.
|
||||
(CommonMethods.Urls): Move to conf/urls.py.
|
||||
(CommonMethods.ExpectedRetcode): Move to conf/expected_retcode.py.
|
||||
(CommonMethods.ExpectedFiles): Move to conf/expected_files.py.
|
||||
(CommonMethods.FilesCrawled): Move to conf/files_crawled.py.
|
||||
(CommonMethods.__check_downloaded_files): Rename to
|
||||
_check_downloaded_files, so that the method is callable from outside the
|
||||
class.
|
||||
(CommomMethods.get_server_rules): Modify so that it utilizes the conf
|
||||
package.
|
||||
(HTTPTest): Add a method hook_call(configs, name) to reduce duplications
|
||||
in pre_hook_call, call_test and post_hook_call utilizing the conf package.
|
||||
* conf/hook_sample.py: (new file) sample for hooks
|
||||
* conf/rule_sample.py: (new file) sample for rules
|
||||
* REAMDE: Update sections about customizing rules and hooks.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* exc: (new package) package for miscellaneous exceptions
|
||||
* WgetTest.py: Move TestFailed to exc/test_failed.py.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* Test-Proto.py: Fix a typo (line 71: server to servers).
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* WgetTest.py: Move WgetFile to package misc.
|
||||
* README: Modify documentation respect to WgetFile.
|
||||
* Test-*.py: Optimize imports about WgetFile.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* misc: (new package) package for miscellaneous modules
|
||||
* ColourTerm.py: Move to package misc and rename to colour_terminal.py,
|
||||
add print_color functions to reduce the use of string literals like
|
||||
"BLUE", "RED" etc.
|
||||
* WgetTest.py:
|
||||
(CommonMethods.Server_setup): Change invocation to printer to print_blue.
|
||||
(CommonMethods.FilesCrawled): Change invocation to printer to print_red.
|
||||
(HTTPTest.__init__): Change invocations to printer to print_red and
|
||||
print_green respectively.
|
||||
|
||||
2014-01-02 Darshit Shah <darnir@gmail.com>
|
||||
* Makefile.am: Add new Test--https.py to list of tests and EXTRA_DIST.
|
||||
Also replace all tabs with spaces in file for conformity.
|
||||
* Test--https.py: New test to check if Wget works correctly with HTTPS
|
||||
servers
|
||||
* HTTPServer.py: Import new modules for use in HTTPS Servers
|
||||
(HTTPSServer): New class that generates a SSL-wrapped socket for use in a
|
||||
HTTPS Server.
|
||||
(HTTPSd): HTTPS daemon class. Analogous to the HTTPd class
|
||||
* WgetTest.py: Define global variables HTTP and HTTPS to reflect Server
|
||||
types
|
||||
(CommonMethods.exec_wget): Add the protocol information to the URL before
|
||||
passing it to wget
|
||||
(HTTPTest.__init__): Edit syntax. The servers variable now accepts a list of
|
||||
servers defined by their type. E.g. HTTP, HTTPS.
|
||||
(HTTPTest.Server_setup): Reflect change in type of variable servers.
|
||||
However, we maintin the value of self.servers to allow most of the code to
|
||||
remain unchanged.
|
||||
(HTTPTest.init_HTTPS_Server): Initialize a HTTPS Server
|
||||
* Test-Parallel-Proto.py: Edit to reflect slight change in Test Fiel Syntax.
|
||||
* Test-Proto.py: Same
|
||||
|
||||
2014-01-02 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMentods.exec_wget): Wait for n seconds before calling
|
||||
the Wget executable.
|
||||
|
||||
2013-12-27 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py: Add modeline
|
||||
(CommonMethods.ServerConf): New pre-test hook that sets
|
||||
BaseHTTPRequestHandler class variables in all available servers
|
||||
* HTTPServer.py (HTTPd.ServerConf): Call the respective method in the Server
|
||||
to set the class variables
|
||||
(StoppableHTTPServer.server_sett): Set the handler class variables
|
||||
|
||||
2013-12-26 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.call_test): Correct the call to stop_HTTP_Server.
|
||||
|
||||
2013-12-25 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMehtods.exec_wget): Catch and handle exception if the
|
||||
Wget executable is not found at src/wget
|
||||
(HTTPTest.call_test): In case of error during execution, remove all existing
|
||||
servers before quitting
|
||||
|
||||
2013-12-15 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.HTTP_setup): Rename to Server_setup so it can be
|
||||
easily reused for other non-HTTP servers.
|
||||
(HTTPTest.__init__): Call Server_setup instead of HTTP_setup
|
||||
(HTTPTest.Server_setup): Split into three more functions, that handle
|
||||
pre-hooks, test execution and post-hooks respectively.
|
||||
(HTTPTest.pre_hook_call): Set up and execute the pre-test hooks. Code split
|
||||
from HTTPTest.Server_setup
|
||||
(HTTPTest.call_test): Execute wget and log exit code. Code split from
|
||||
HTTPTest.Server_setup
|
||||
(HTTPTest.post_hook_call): Set up and execute post-test hooks. Code split
|
||||
from HTTPTest.Server_setup
|
||||
|
||||
2013-12-04 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Makefile.am [RACE_CHECKING_IS_ENABLED]: Define `RACE_FAIL' and
|
||||
RACE_TESTS'.
|
||||
|
||||
2013-10-14 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.am (XFAIL_TESTS): Remove Test--spider-r.py.
|
||||
|
||||
2013-10-06 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.am (EXTRA_DIST): Distribute test files.
|
||||
|
||||
2013-09-16 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: Update documentation
|
||||
|
||||
2013-09-14 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (StoppableHTTPServer): Define object variable
|
||||
request_headers which stores a list of requests received by the server
|
||||
(StoppableHTTPServer.get_req_headers): Return the list of Request
|
||||
Headers stored by the server
|
||||
(_Handler.do_HEAD): Send the Request MEthod string for identification
|
||||
(_Handler.do_GET): Same
|
||||
(_Handler.__log_request): Log the request in Request_Headers list
|
||||
(_Handler.send_head): Make a call to __log_request
|
||||
* Test--spider-r.py: Add new list, Request_List, which contains all
|
||||
the requests that Wget is expected to send. This will allow for
|
||||
fine-grained tests on recursive downloading.
|
||||
* WgetTest.py (CommonMethods.FilesCrawled): New Post-Test Hook, that
|
||||
ensures that all the expected Files on the server were accessed as
|
||||
expected.
|
||||
(HTTPTest.stop_HTTP_server): On stopping server, asks it to respond
|
||||
with list of all requests it received.
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test--spider-r.py: Test retrieval in recursive spider mode.
|
||||
* Makefile.am: add new file
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (_Handler.do_HEAD): If requested path is /, respond
|
||||
with /index.html
|
||||
(_Handler.do_HEAD): Smartly guess value of Content-Type Header from
|
||||
file extension
|
||||
(_Handler.guess_type): Use a preset list of extensions and
|
||||
Content-Type strings. If the extension matches one in the list, use
|
||||
that string, else default to "text/plain"
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods._replace_substring): New method that will
|
||||
replace a substring delimited by {{ }} characters by the value of
|
||||
self.<substring> variable
|
||||
(CommonMethods.WgetCommands): Use the _replace_substring () call to
|
||||
replace the substrings in the the command line.
|
||||
(CommonMethods.ServerFiles): Run the _replace_substring () method on
|
||||
the File contents too.
|
||||
|
||||
2013-09-11 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods.exec_wget): Expect domain_list instead of
|
||||
domain.
|
||||
(CommonMethods.get_cmd_line): Same. Generate command line by
|
||||
prepending to each file it's respective domain string
|
||||
(CommonMethods.ServerFiles): Generate file_list and server_rules for
|
||||
each Server and set the config details
|
||||
(HTTPTest): New named parameter, servers which signifies number of
|
||||
servers to spawn
|
||||
(HTTPTest.HTTP_setup): This method now takes servers as a new
|
||||
parameter. Instead of storing server and domain, we now store
|
||||
server_list and domain_list. Each server must be initialized through a
|
||||
loop.
|
||||
(HTTPTest.stop_HTTP_server): Stop all servers in a loop.
|
||||
* Test-Parallel-Proto.py: Prototype test file for multiple servers.
|
||||
|
||||
2013-09-10 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.stop_HTTP_server): With the threaded servers,
|
||||
we can simply use the socketserver.shutdown() method to close the
|
||||
server instead of sending a QUIT command
|
||||
* HTTPServer.py (StoppabelHTTPServer.serve_forever): Delete method. No
|
||||
need to override this method anymore.
|
||||
(WgetHTTPRequestHandler.do_QUIT): No longer required
|
||||
(HTTPd): Rename self.server to self.server_inst to reduce ambiguity
|
||||
when referenced from WgetTest
|
||||
|
||||
2013-09-08 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README (File Structure): Add explanation about various variables
|
||||
used consistently across all tests.
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py: Remove bunch of old code artefacts
|
||||
* WgetTest.py: Same
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (StoppableHTTPServer.server_conf): Change global
|
||||
variable fileSys to an object variable. This is good programming
|
||||
practice and required for parallel-wget support.
|
||||
(StoppableHTTPServer.server_forever): Edit overridden method to remove
|
||||
the global queue variable. No longer required under the new working
|
||||
(WgetHTTPRequestHandler.do_QUIT): Don't push fileSys through the queue
|
||||
(_Handler): Rename class __Handler to _Handler to match Python's
|
||||
encapsulation rules
|
||||
(_Handler.do_POST): fileSys is now an object variable of the server
|
||||
(_Handler.do_PUT): Same
|
||||
(_Handler.send_put): Same
|
||||
(_Handler.send_head): Same
|
||||
(HTTPd): New class that wraps around the server for Threading
|
||||
(create_server): Make new object of HTTPd.
|
||||
(spawn_server): Start the thread created through create_server
|
||||
(ret_fileSys): Removed method. No longer required.
|
||||
* WgetTest.py (HTTPTest.__init__): Don't explicitly set
|
||||
self.act_retcode. Instead toggle tests_passed boolean to set the
|
||||
correct return code.
|
||||
(HTTPTest.HTTP_setup): We no longer call HTTPServer.spawn_server to
|
||||
start a new instance of the server.
|
||||
(HTTPTest.init_HTTP_server): We no longer call the old
|
||||
create_server(), spawn_server() methods. Instead use the new HTTPd
|
||||
class interface to create new instances of the server
|
||||
(HTTPTest.stop_HTTP_server): Don't ask server to return fileSys.
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-Post.py: Test basic functionality for sending HTTP POST
|
||||
requests using the --method command
|
||||
* Makefile.am: Add new test
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods.__check_downloaded_files): Print a
|
||||
unified diff in case there is a mismatch in the file contents
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (WgetHTTPRequestHandler.test_cookies): Comment out the
|
||||
old test_cookies code. This is no longer used and was causing problems
|
||||
with expected cookies. The code will soon be removed anyways
|
||||
* Test-cookie.py: Add new test for basic cookie functionality
|
||||
* Test-cookie-401.py: Ensure cookies are saved during a 401 response
|
||||
* Test-cookie-expires.py: Ensure that the Expires field is correctly
|
||||
handled
|
||||
* Test-cookies-domain-mismatch.py: Ensure that mismatched domains are
|
||||
handled by Wget
|
||||
* Makefile.am: Add the new tests
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: New section on pending work. Will keep updating this to keep
|
||||
track of work that remains to be done on this implementation
|
||||
|
||||
2013-09-05 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-auth-with-content-disposition.py: Add test that ensures Content
|
||||
Disposition works alongwith authentication
|
||||
* Makefile.am: Add new test
|
||||
|
||||
2013-09-04 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-c-full.py: Test Continue options
|
||||
* Makefile.am: Add Test-c-full.py and Test-O
|
||||
|
||||
2013-09-02 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Makefile.am: Add new Test
|
||||
* Test-Head.py: New Test to ensure HEAD requests are handled correctly
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: Explain that TEST_NAME needs to be unique
|
||||
* Test-auth-no-challenge.py: Edit non-unique TEST_NAME
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPTest.py (ServerError): Define new Exception for handling
|
||||
internal control flow.
|
||||
(StoppableHTTPServer.SendHeader): Simply pass. Do nothing. Adding
|
||||
functionality here seems to crash for no apparent reason.
|
||||
(stoppableHTTPServer.send_cust_headers): Minor optimization. No need
|
||||
for extra variable.
|
||||
(__Handler.Response): Handle explicit Response Code Rules
|
||||
(__Handler.Authentication): Handle Authentication rules
|
||||
(__Handler.handle_auth): Actual worker method for authentication
|
||||
(__Handler.ExpectHeader): Ensure Expected Headers are received
|
||||
(__Handler.RejectHeader): Ensure Blacklisted Headers are NOT received
|
||||
(__Handler.send_HEAD): Dynamically call server rule functions based on
|
||||
the self.rules list. This feature will later be added to POST/PUT, etc
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py: Remove import module defaultdict.
|
||||
(CommonMethods.get_server_rules): server_rules should be a dict, not a
|
||||
defaultdict (list).
|
||||
* HTTPServer.py (WgetHTTPRequestHandler.get_rule_list): If rule does
|
||||
not exist, return None. Not an emppty list.
|
||||
(WgetHTTPRequestHandler.test_cookies): Rule variable is not a list
|
||||
(__Handler.send_cust_headers): Same
|
||||
(__Handler.custom_response): Same
|
||||
(__Handler.is_authorized): Same
|
||||
(__Handler.expect_headers): Same
|
||||
(__Handler.reject_headers): Same
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: (newfile) Simple help / instructions about using the Test
|
||||
Environment.
|
||||
* Makefile.am: (newfile) Makefile for the Test Environment. Uses the
|
||||
Automake Parallel Test Harness
|
||||
* WgetTest.py: (newfile) Base module that executes the Test.
|
||||
* HTTPServer.py: (newfile) Contains the custom HTTP Server for the
|
||||
Test Environment. Creates an instance of http.server in Python3.
|
||||
* FTPServer.py: (newfile) Overrides methods from pyftpdlib for use in
|
||||
the Test Environment. ** Work under progress **.
|
||||
* ColourTerm.py: (newfile) A custom module to output coloured text to
|
||||
the terminal. Known to work on POSIX shells.
|
||||
* Test-Proto.py: (newfile) A prototype Test File. This should be
|
||||
copied when writing a new Test Case.
|
||||
* Test-Content-disposition-2.py: Test Content Disposition clobbering
|
||||
* Test-Content-disposition.py: Test Content Disposition Headers
|
||||
* Test-O.py: Test Output filename command
|
||||
* Test-auth-basic-fail.py: Test returncode on auth failure
|
||||
* Test-auth-basic.py: Test Basic Auth negotiation
|
||||
* Test-auth-both.py: Test handling of Multiple auth providers. This
|
||||
test currently fails.
|
||||
* Test-auth-digest.py: Test Digest Auth Negotiation
|
||||
* Test-auth-no-challenge-url.py: Ensure --auth-no-challenge is handled
|
||||
when auth details are in-URL.
|
||||
* Test-auth-no-challenge.py: Ensure --auth-no-challenge is honoured
|
||||
* Test-auth-retcode.py: Ensure correct return code after 403 Forbidden
|
||||
response.
|
||||
2014-08-08 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* conf/__init__.py: Add extra newline according to PEP8
|
||||
* conf/{authentication,expect_header,expected_files,expected_ret_code,
|
||||
files_crawled,hook_sample,local_files,reject_header,response,send_header,
|
||||
server_files,urls,wget_commands}.py: Add docstrings explaining the conf file
|
||||
and how it should be used
|
||||
* server/http/http_server (InvalidRangeHeader): Clear TODO and eliminate
|
||||
this exception. Use ServerError for all such purposes.
|
||||
(_Handler): Remove reference to InvalidRangeHeader
|
||||
(_handler.parse_range_header): User ServerError instead of InvalidRangeHeader
|
||||
(_Handler.do_GET): Add docstring
|
||||
(_Handler.do_POST): Add docstring. Also create an empty dict for rules if
|
||||
no rules are supplied. Send the Location header as suggested in RFC 7231
|
||||
(_Handler.do_PUT): Don't pop the server file already. Push it to later in ..
|
||||
(_Handler.send_put): .. Here. If the file exists respond with a 204 No
|
||||
Content message and pop the file for replacement. Do not send the
|
||||
Content-Length, Content-Type headers since PUT requests should not respond
|
||||
with data.
|
||||
(_Handler.parse_auth_header): Fit line within 80 chars
|
||||
(_Handler.check_response): Better visual indent
|
||||
(_Handler.authorize_digest): Better visual indent.
|
||||
(_Handler.expect_headers): Remove unused function
|
||||
(_Handler.guess_type): Fix indentation
|
||||
(HTTPd): Add newline according to PEP8 guidelines
|
||||
(HTTPSd): Fix indentation
|
||||
(StoppableHTTPServer): Add docstring
|
||||
(HTTPSServer): Fix indentation
|
||||
(WgetHTTPRequestHandler): Merge class into _handler.
|
||||
(_Handler): Add docstring
|
||||
(_Handler.parse_range_header): Fix indentation
|
||||
(ServerError): Split exception into separate file ...
|
||||
* exc/server_error.py: ... Here
|
||||
* misc/colour_terminal.py: Add docstring, fix indentation
|
||||
* test/base_test.py: Fix visual indent
|
||||
* test/http_test.py: Fit within 80 char lines
|
||||
|
||||
2014-08-04 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* conf/server_conf.py: Delete file. Server configuration is now done via the
|
||||
server_conf() method.
|
||||
* server/http/http_server.py (StppableHTTPServer.server_sett): Delete
|
||||
method required by the above hook
|
||||
(HTTPd.server_sett): Same
|
||||
|
||||
2014-07-26 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-*.py: Remove the '-d' switch from WGET_OPTIONS.
|
||||
* test/base_test (BaseTest.gen_cmd_line): Add --debug and --no-config to the
|
||||
list of switches passed to wget unconditionally.
|
||||
|
||||
2014-07-23 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* test/base_test.py (BaseTest.gen_cmd_line): Add support for running all
|
||||
tests through valgrind if the relevant environment variable is set
|
||||
* conf/expected_ret_code (ExpectedRetCode.__call__): Valgrind returns error
|
||||
code 45 when it detects a memory leak.
|
||||
* Readme: Update with details about valgrind tests
|
||||
|
||||
2014-07-22 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* (README): Remove old TODO and document SERVER_WAIT variable
|
||||
|
||||
2014-06-22 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* (conf.files_crawled): diff is a set object and needs explicit str
|
||||
conversion.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* base_test.py:
|
||||
(CommonMethods): Rename to BaseTest.
|
||||
(BaseTest): Implement __init__ method where the class-wide variables are
|
||||
initialized. Also variable names like `xxx_list` is renamed to its plural
|
||||
form, e.g. `server_list` => `servers`.
|
||||
(BaseTest.init_test_env): Remove name argument due to its unnecessarity.
|
||||
(BaseTest.get_test_dir): Because the path of the test directory is needed
|
||||
in multiple methods, this method is implemented.
|
||||
(BaseTest.get_domain_addr): Rewrite the return statement utilizing str
|
||||
formatting (which is more Pythonic).
|
||||
(BaseTest.get_cmd_line): Rename to gen_cmd_line. Change the variables with
|
||||
capitcal characters to lower ones. Also, the nested for loop is rewritten
|
||||
to a plain loop using the zip function.
|
||||
(BaseTest.__gen_local_filesys): Rename to gen_local_fs_snapshot. Move to
|
||||
ExpectedFiles in conf/expected_files.py and is marked as a static
|
||||
method. Refactor to a less verbose implementation.
|
||||
(BaseTest._check_downloaded_files): Rename to __call__ to agree with the
|
||||
invocation in test case classes. Move to ExpectedFiles in
|
||||
conf/expected_files.py.
|
||||
(BaseTest.get_server_rules): Refactor to a more Pythonic form utilizing
|
||||
dict.items() and is marked static.
|
||||
(BaseTest.stop_server): (new method) an abstract method which should stop
|
||||
the currently using servers.
|
||||
(BaseTest.instantiate_server_by): (new method) an abstract method which
|
||||
should instantiate a server instance according to the given argument.
|
||||
(BaseTest.__enter__): (new method) method which initialize the context
|
||||
manager
|
||||
(BaseTest.__exit__): (new method) method that finilize the context manager
|
||||
and deal with the exceptions during the execution of the with statement,
|
||||
subclasses can override this method for extensibility
|
||||
* http_test.py:
|
||||
(HTTPTest.__init__): Add call to super.__init__. Default values of
|
||||
pre_hook, test_params, post_hook are set to None to avoid a subtle bug of
|
||||
Python. Argument servers is renamed to protocols.
|
||||
(HTTPTest.Server_setup): Move to BaseTest and rename to server_setup.
|
||||
Calls to pre_hook_call, call_test, post_hook_call are removed.
|
||||
(HTTPTest.hook_call, pre_hook_call, call_test, post_hook_call): Move to
|
||||
BaseTest for that both HTTP test cases and FTP test cases may use these
|
||||
methods.
|
||||
(HTTPTest.init_HTTP_Server, init_HTTPS_Server): Merge and rename to
|
||||
instantiate_server_by to implement the abstract method in BaseTest.
|
||||
(HTTPTest.stop_HTTP_Server): Rename to stop_server to implement the
|
||||
abstract method in BaseTest. Also, pull out the part where remaining
|
||||
requests are gathered into a new method request_remaining.
|
||||
(BaseTest.act_retcode): Rename to ret_code because ExpectedRetCode is
|
||||
moved out from BaseTest, so the name act_retcode is actually a bit
|
||||
verbose.
|
||||
* conf/expected_ret_code.py:
|
||||
(ExpectedRetCode.__call__): Rewrite the str into a more readable form.
|
||||
* conf/files_crawled.py:
|
||||
(FilesCrawled.__call__): Refactor this method into a more Pythonic form
|
||||
utilizing the zip function.
|
||||
* conf/local_files.py:
|
||||
(LocalFiles__call__): Rewrite this method with the recommended with
|
||||
statement.
|
||||
* conf/server_conf.py:
|
||||
(ServerConf.__call__): Rewrite this method due to BaseTest.server_list is
|
||||
renamed to BaseTest.servers.
|
||||
* conf/server_files.py:
|
||||
(ServerFiles.__call__): Refactor the nested for loop into a plain one
|
||||
utilizing the zip function.
|
||||
* conf/urls.py:
|
||||
(URLs): Rename url_list to urls.
|
||||
* conf/wget_commands.py:
|
||||
(WgetCommands): Rename command_list to commands, rename test_obj.options
|
||||
to test_obj.wget_options.
|
||||
* Test--https.py, Test-Proto.py, Test-Parallel-Proto.py: Argument servers
|
||||
is changed to protocols due to change in the signature of
|
||||
HTTPTest.__init__.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* test: (new package) package for test case classes
|
||||
* WgetTest.py: Split into test/base_test.py and test/http_test.py.
|
||||
* Test-*.py: Optimize the imports according to changes of WgetTest.py
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* server: (new package) package for the server classes
|
||||
* server.http: (new package) package for HTTP server
|
||||
* server.ftp: (new package) package for FTP server
|
||||
* HTTPServer.py: Move to server/http/http_server.py. Also change the
|
||||
CERTFILE to '../certs/wget-cert.pem'.
|
||||
* FTPServer.py: Move to server/ftp/ftp_server.py.
|
||||
* WgetTest.py: Optimize import respect to the server classes.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* conf: (new package) package for rule classes and hook methods
|
||||
* WgetTest.py:
|
||||
(CommonMethods.Authentication): Move to conf/authentication.py.
|
||||
(CommonMethods.ExpectHeader): Move to conf/expect_header.py.
|
||||
(CommonMethods.RejectHeader): Move to conf/reject_header.py.
|
||||
(CommonMethods.Response): Move to conf/response.py.
|
||||
(CommonMethods.SendHeader): Move to conf/send_header.py.
|
||||
(CommonMethods.ServerFiles): Move to conf/server_files.py.
|
||||
(CommonMethods.LocalFiles): Move to conf/local_files.py.
|
||||
(CommonMethods.ServerConf): Move to conf/server_conf.py.
|
||||
(CommonMethods.WgetCommands): Move to conf/wget_commands.py.
|
||||
(CommonMethods.Urls): Move to conf/urls.py.
|
||||
(CommonMethods.ExpectedRetcode): Move to conf/expected_retcode.py.
|
||||
(CommonMethods.ExpectedFiles): Move to conf/expected_files.py.
|
||||
(CommonMethods.FilesCrawled): Move to conf/files_crawled.py.
|
||||
(CommonMethods.__check_downloaded_files): Rename to
|
||||
_check_downloaded_files, so that the method is callable from outside the
|
||||
class.
|
||||
(CommomMethods.get_server_rules): Modify so that it utilizes the conf
|
||||
package.
|
||||
(HTTPTest): Add a method hook_call(configs, name) to reduce duplications
|
||||
in pre_hook_call, call_test and post_hook_call utilizing the conf package.
|
||||
* conf/hook_sample.py: (new file) sample for hooks
|
||||
* conf/rule_sample.py: (new file) sample for rules
|
||||
* REAMDE: Update sections about customizing rules and hooks.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* exc: (new package) package for miscellaneous exceptions
|
||||
* WgetTest.py: Move TestFailed to exc/test_failed.py.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* Test-Proto.py: Fix a typo (line 71: server to servers).
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* WgetTest.py: Move WgetFile to package misc.
|
||||
* README: Modify documentation respect to WgetFile.
|
||||
* Test-*.py: Optimize imports about WgetFile.
|
||||
|
||||
2014-03-13 Zihang Chen <chsc4698@gmail.com>
|
||||
|
||||
* misc: (new package) package for miscellaneous modules
|
||||
* ColourTerm.py: Move to package misc and rename to colour_terminal.py,
|
||||
add print_color functions to reduce the use of string literals like
|
||||
"BLUE", "RED" etc.
|
||||
* WgetTest.py:
|
||||
(CommonMethods.Server_setup): Change invocation to printer to print_blue.
|
||||
(CommonMethods.FilesCrawled): Change invocation to printer to print_red.
|
||||
(HTTPTest.__init__): Change invocations to printer to print_red and
|
||||
print_green respectively.
|
||||
|
||||
2014-01-02 Darshit Shah <darnir@gmail.com>
|
||||
* Makefile.am: Add new Test--https.py to list of tests and EXTRA_DIST.
|
||||
Also replace all tabs with spaces in file for conformity.
|
||||
* Test--https.py: New test to check if Wget works correctly with HTTPS
|
||||
servers
|
||||
* HTTPServer.py: Import new modules for use in HTTPS Servers
|
||||
(HTTPSServer): New class that generates a SSL-wrapped socket for use in a
|
||||
HTTPS Server.
|
||||
(HTTPSd): HTTPS daemon class. Analogous to the HTTPd class
|
||||
* WgetTest.py: Define global variables HTTP and HTTPS to reflect Server
|
||||
types
|
||||
(CommonMethods.exec_wget): Add the protocol information to the URL before
|
||||
passing it to wget
|
||||
(HTTPTest.__init__): Edit syntax. The servers variable now accepts a list of
|
||||
servers defined by their type. E.g. HTTP, HTTPS.
|
||||
(HTTPTest.Server_setup): Reflect change in type of variable servers.
|
||||
However, we maintin the value of self.servers to allow most of the code to
|
||||
remain unchanged.
|
||||
(HTTPTest.init_HTTPS_Server): Initialize a HTTPS Server
|
||||
* Test-Parallel-Proto.py: Edit to reflect slight change in Test Fiel Syntax.
|
||||
* Test-Proto.py: Same
|
||||
|
||||
2014-01-02 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMentods.exec_wget): Wait for n seconds before calling
|
||||
the Wget executable.
|
||||
|
||||
2013-12-27 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py: Add modeline
|
||||
(CommonMethods.ServerConf): New pre-test hook that sets
|
||||
BaseHTTPRequestHandler class variables in all available servers
|
||||
* HTTPServer.py (HTTPd.ServerConf): Call the respective method in the Server
|
||||
to set the class variables
|
||||
(StoppableHTTPServer.server_sett): Set the handler class variables
|
||||
|
||||
2013-12-26 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.call_test): Correct the call to stop_HTTP_Server.
|
||||
|
||||
2013-12-25 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMehtods.exec_wget): Catch and handle exception if the
|
||||
Wget executable is not found at src/wget
|
||||
(HTTPTest.call_test): In case of error during execution, remove all existing
|
||||
servers before quitting
|
||||
|
||||
2013-12-15 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.HTTP_setup): Rename to Server_setup so it can be
|
||||
easily reused for other non-HTTP servers.
|
||||
(HTTPTest.__init__): Call Server_setup instead of HTTP_setup
|
||||
(HTTPTest.Server_setup): Split into three more functions, that handle
|
||||
pre-hooks, test execution and post-hooks respectively.
|
||||
(HTTPTest.pre_hook_call): Set up and execute the pre-test hooks. Code split
|
||||
from HTTPTest.Server_setup
|
||||
(HTTPTest.call_test): Execute wget and log exit code. Code split from
|
||||
HTTPTest.Server_setup
|
||||
(HTTPTest.post_hook_call): Set up and execute post-test hooks. Code split
|
||||
from HTTPTest.Server_setup
|
||||
|
||||
2013-10-14 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.am (XFAIL_TESTS): Remove Test--spider-r.py.
|
||||
|
||||
2013-10-06 Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
|
||||
* Makefile.am (EXTRA_DIST): Distribute test files.
|
||||
|
||||
2013-09-16 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: Update documentation
|
||||
|
||||
2013-09-14 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (StoppableHTTPServer): Define object variable
|
||||
request_headers which stores a list of requests received by the server
|
||||
(StoppableHTTPServer.get_req_headers): Return the list of Request
|
||||
Headers stored by the server
|
||||
(_Handler.do_HEAD): Send the Request MEthod string for identification
|
||||
(_Handler.do_GET): Same
|
||||
(_Handler.__log_request): Log the request in Request_Headers list
|
||||
(_Handler.send_head): Make a call to __log_request
|
||||
* Test--spider-r.py: Add new list, Request_List, which contains all
|
||||
the requests that Wget is expected to send. This will allow for
|
||||
fine-grained tests on recursive downloading.
|
||||
* WgetTest.py (CommonMethods.FilesCrawled): New Post-Test Hook, that
|
||||
ensures that all the expected Files on the server were accessed as
|
||||
expected.
|
||||
(HTTPTest.stop_HTTP_server): On stopping server, asks it to respond
|
||||
with list of all requests it received.
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test--spider-r.py: Test retrieval in recursive spider mode.
|
||||
* Makefile.am: add new file
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (_Handler.do_HEAD): If requested path is /, respond
|
||||
with /index.html
|
||||
(_Handler.do_HEAD): Smartly guess value of Content-Type Header from
|
||||
file extension
|
||||
(_Handler.guess_type): Use a preset list of extensions and
|
||||
Content-Type strings. If the extension matches one in the list, use
|
||||
that string, else default to "text/plain"
|
||||
|
||||
2013-09-13 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods._replace_substring): New method that will
|
||||
replace a substring delimited by {{ }} characters by the value of
|
||||
self.<substring> variable
|
||||
(CommonMethods.WgetCommands): Use the _replace_substring () call to
|
||||
replace the substrings in the the command line.
|
||||
(CommonMethods.ServerFiles): Run the _replace_substring () method on
|
||||
the File contents too.
|
||||
|
||||
2013-09-11 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods.exec_wget): Expect domain_list instead of
|
||||
domain.
|
||||
(CommonMethods.get_cmd_line): Same. Generate command line by
|
||||
prepending to each file it's respective domain string
|
||||
(CommonMethods.ServerFiles): Generate file_list and server_rules for
|
||||
each Server and set the config details
|
||||
(HTTPTest): New named parameter, servers which signifies number of
|
||||
servers to spawn
|
||||
(HTTPTest.HTTP_setup): This method now takes servers as a new
|
||||
parameter. Instead of storing server and domain, we now store
|
||||
server_list and domain_list. Each server must be initialized through a
|
||||
loop.
|
||||
(HTTPTest.stop_HTTP_server): Stop all servers in a loop.
|
||||
* Test-Parallel-Proto.py: Prototype test file for multiple servers.
|
||||
|
||||
2013-09-10 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (HTTPTest.stop_HTTP_server): With the threaded servers,
|
||||
we can simply use the socketserver.shutdown() method to close the
|
||||
server instead of sending a QUIT command
|
||||
* HTTPServer.py (StoppabelHTTPServer.serve_forever): Delete method. No
|
||||
need to override this method anymore.
|
||||
(WgetHTTPRequestHandler.do_QUIT): No longer required
|
||||
(HTTPd): Rename self.server to self.server_inst to reduce ambiguity
|
||||
when referenced from WgetTest
|
||||
|
||||
2013-09-08 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README (File Structure): Add explanation about various variables
|
||||
used consistently across all tests.
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py: Remove bunch of old code artefacts
|
||||
* WgetTest.py: Same
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (StoppableHTTPServer.server_conf): Change global
|
||||
variable fileSys to an object variable. This is good programming
|
||||
practice and required for parallel-wget support.
|
||||
(StoppableHTTPServer.server_forever): Edit overridden method to remove
|
||||
the global queue variable. No longer required under the new working
|
||||
(WgetHTTPRequestHandler.do_QUIT): Don't push fileSys through the queue
|
||||
(_Handler): Rename class __Handler to _Handler to match Python's
|
||||
encapsulation rules
|
||||
(_Handler.do_POST): fileSys is now an object variable of the server
|
||||
(_Handler.do_PUT): Same
|
||||
(_Handler.send_put): Same
|
||||
(_Handler.send_head): Same
|
||||
(HTTPd): New class that wraps around the server for Threading
|
||||
(create_server): Make new object of HTTPd.
|
||||
(spawn_server): Start the thread created through create_server
|
||||
(ret_fileSys): Removed method. No longer required.
|
||||
* WgetTest.py (HTTPTest.__init__): Don't explicitly set
|
||||
self.act_retcode. Instead toggle tests_passed boolean to set the
|
||||
correct return code.
|
||||
(HTTPTest.HTTP_setup): We no longer call HTTPServer.spawn_server to
|
||||
start a new instance of the server.
|
||||
(HTTPTest.init_HTTP_server): We no longer call the old
|
||||
create_server(), spawn_server() methods. Instead use the new HTTPd
|
||||
class interface to create new instances of the server
|
||||
(HTTPTest.stop_HTTP_server): Don't ask server to return fileSys.
|
||||
|
||||
2013-09-07 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-Post.py: Test basic functionality for sending HTTP POST
|
||||
requests using the --method command
|
||||
* Makefile.am: Add new test
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py (CommonMethods.__check_downloaded_files): Print a
|
||||
unified diff in case there is a mismatch in the file contents
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPServer.py (WgetHTTPRequestHandler.test_cookies): Comment out the
|
||||
old test_cookies code. This is no longer used and was causing problems
|
||||
with expected cookies. The code will soon be removed anyways
|
||||
* Test-cookie.py: Add new test for basic cookie functionality
|
||||
* Test-cookie-401.py: Ensure cookies are saved during a 401 response
|
||||
* Test-cookie-expires.py: Ensure that the Expires field is correctly
|
||||
handled
|
||||
* Test-cookies-domain-mismatch.py: Ensure that mismatched domains are
|
||||
handled by Wget
|
||||
* Makefile.am: Add the new tests
|
||||
|
||||
2013-09-06 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: New section on pending work. Will keep updating this to keep
|
||||
track of work that remains to be done on this implementation
|
||||
|
||||
2013-09-05 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-auth-with-content-disposition.py: Add test that ensures Content
|
||||
Disposition works alongwith authentication
|
||||
* Makefile.am: Add new test
|
||||
|
||||
2013-09-04 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Test-c-full.py: Test Continue options
|
||||
* Makefile.am: Add Test-c-full.py and Test-O
|
||||
|
||||
2013-09-02 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* Makefile.am: Add new Test
|
||||
* Test-Head.py: New Test to ensure HEAD requests are handled correctly
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: Explain that TEST_NAME needs to be unique
|
||||
* Test-auth-no-challenge.py: Edit non-unique TEST_NAME
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* HTTPTest.py (ServerError): Define new Exception for handling
|
||||
internal control flow.
|
||||
(StoppableHTTPServer.SendHeader): Simply pass. Do nothing. Adding
|
||||
functionality here seems to crash for no apparent reason.
|
||||
(stoppableHTTPServer.send_cust_headers): Minor optimization. No need
|
||||
for extra variable.
|
||||
(__Handler.Response): Handle explicit Response Code Rules
|
||||
(__Handler.Authentication): Handle Authentication rules
|
||||
(__Handler.handle_auth): Actual worker method for authentication
|
||||
(__Handler.ExpectHeader): Ensure Expected Headers are received
|
||||
(__Handler.RejectHeader): Ensure Blacklisted Headers are NOT received
|
||||
(__Handler.send_HEAD): Dynamically call server rule functions based on
|
||||
the self.rules list. This feature will later be added to POST/PUT, etc
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* WgetTest.py: Remove import module defaultdict.
|
||||
(CommonMethods.get_server_rules): server_rules should be a dict, not a
|
||||
defaultdict (list).
|
||||
* HTTPServer.py (WgetHTTPRequestHandler.get_rule_list): If rule does
|
||||
not exist, return None. Not an emppty list.
|
||||
(WgetHTTPRequestHandler.test_cookies): Rule variable is not a list
|
||||
(__Handler.send_cust_headers): Same
|
||||
(__Handler.custom_response): Same
|
||||
(__Handler.is_authorized): Same
|
||||
(__Handler.expect_headers): Same
|
||||
(__Handler.reject_headers): Same
|
||||
|
||||
2013-08-31 Darshit Shah <darnir@gmail.com>
|
||||
|
||||
* README: (newfile) Simple help / instructions about using the Test
|
||||
Environment.
|
||||
* Makefile.am: (newfile) Makefile for the Test Environment. Uses the
|
||||
Automake Parallel Test Harness
|
||||
* WgetTest.py: (newfile) Base module that executes the Test.
|
||||
* HTTPServer.py: (newfile) Contains the custom HTTP Server for the
|
||||
Test Environment. Creates an instance of http.server in Python3.
|
||||
* FTPServer.py: (newfile) Overrides methods from pyftpdlib for use in
|
||||
the Test Environment. ** Work under progress **.
|
||||
* ColourTerm.py: (newfile) A custom module to output coloured text to
|
||||
the terminal. Known to work on POSIX shells.
|
||||
* Test-Proto.py: (newfile) A prototype Test File. This should be
|
||||
copied when writing a new Test Case.
|
||||
* Test-Content-disposition-2.py: Test Content Disposition clobbering
|
||||
* Test-Content-disposition.py: Test Content Disposition Headers
|
||||
* Test-O.py: Test Output filename command
|
||||
* Test-auth-basic-fail.py: Test returncode on auth failure
|
||||
* Test-auth-basic.py: Test Basic Auth negotiation
|
||||
* Test-auth-both.py: Test handling of Multiple auth providers. This
|
||||
test currently fails.
|
||||
* Test-auth-digest.py: Test Digest Auth Negotiation
|
||||
* Test-auth-no-challenge-url.py: Ensure --auth-no-challenge is handled
|
||||
when auth details are in-URL.
|
||||
* Test-auth-no-challenge.py: Ensure --auth-no-challenge is honoured
|
||||
* Test-auth-retcode.py: Ensure correct return code after 403 Forbidden
|
||||
response.
|
||||
90
testenv/Makefile.am
Normal file
90
testenv/Makefile.am
Normal file
@@ -0,0 +1,90 @@
|
||||
# Makefile for `wget' utility
|
||||
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
# If you modify this program, or any covered work, by linking or
|
||||
# combining it with the OpenSSL project's OpenSSL library (or a
|
||||
# modified version of that library), containing parts covered by the
|
||||
# terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
# grants you additional permission to convey the resulting work.
|
||||
# Corresponding Source for a non-source form of such a combination
|
||||
# shall include the source code for the parts of OpenSSL used as well
|
||||
# as that of the covered work.
|
||||
|
||||
|
||||
AUTOMAKE_OPTIONS = parallel-tests
|
||||
AM_TESTS_ENVIRONMENT = MAKE_CHECK=True; export MAKE_CHECK;
|
||||
|
||||
if RACE_CHECKING_IS_ENABLED
|
||||
RACE_FAIL = Test--spider-r.py
|
||||
RACE_TESTS =
|
||||
endif
|
||||
|
||||
TESTS = Test-auth-basic-fail.py \
|
||||
Test-auth-basic.py \
|
||||
Test-auth-both.py \
|
||||
Test-auth-digest.py \
|
||||
Test-auth-no-challenge.py \
|
||||
Test-auth-no-challenge-url.py \
|
||||
Test-auth-retcode.py \
|
||||
Test-auth-with-content-disposition.py \
|
||||
Test-c-full.py \
|
||||
Test-Content-disposition-2.py \
|
||||
Test-Content-disposition.py \
|
||||
Test-cookie-401.py \
|
||||
Test-cookie-domain-mismatch.py \
|
||||
Test-cookie-expires.py \
|
||||
Test-cookie.py \
|
||||
$(RACE_TESTS) \
|
||||
Test-Head.py \
|
||||
Test--https.py \
|
||||
Test-O.py \
|
||||
Test-Post.py \
|
||||
Test--spider-r.py
|
||||
|
||||
XFAIL_TESTS = Test-auth-both.py \
|
||||
$(RACE_FAIL)
|
||||
|
||||
LOG_COMPILER = python3
|
||||
|
||||
EXTRA_DIST = ColourTerm.py \
|
||||
FTPServer.py \
|
||||
HTTPServer.py \
|
||||
README \
|
||||
Test--spider-r.py \
|
||||
Test--https.py \
|
||||
Test-Content-disposition-2.py \
|
||||
Test-Content-disposition.py \
|
||||
Test-Head.py \
|
||||
Test-O.py \
|
||||
Test-Parallel-Proto.py \
|
||||
Test-Post.py \
|
||||
Test-Proto.py \
|
||||
Test-auth-basic-fail.py \
|
||||
Test-auth-basic.py \
|
||||
Test-auth-both.py \
|
||||
Test-auth-digest.py \
|
||||
Test-auth-no-challenge-url.py \
|
||||
Test-auth-no-challenge.py \
|
||||
Test-auth-retcode.py \
|
||||
Test-auth-with-content-disposition.py \
|
||||
Test-c-full.py \
|
||||
Test-cookie-401.py \
|
||||
Test-cookie-domain-mismatch.py \
|
||||
Test-cookie-expires.py \
|
||||
Test-cookie.py \
|
||||
WgetTest.py
|
||||
303
testenv/README
Normal file
303
testenv/README
Normal file
@@ -0,0 +1,303 @@
|
||||
This document describes the working of the GNU Wget Test Suite.
|
||||
|
||||
Install Instructions:
|
||||
================================================================================
|
||||
|
||||
This Test Suite exploits the Parallel Test Harness available in GNU Autotools.
|
||||
Since it uses features from a relatively recent verion of Autotools, the minimum
|
||||
required version as been bumped up to 1.11.
|
||||
Run the './configure' command to generate the Makefile and then run 'make check'
|
||||
to execute the Test Suite. Use the '-j n' option with 'make check' to execute
|
||||
n tests simultaneously.
|
||||
|
||||
Structure:
|
||||
================================================================================
|
||||
|
||||
* server: This package contains custom programmatically configurable servers
|
||||
(both HTTP and FTP) for testing Wget. The HTTP server runs an instance of
|
||||
Python's http.server module. The FTP server is to be implemented.
|
||||
|
||||
* test: This package contains the test case classes for HTTP and FTP. The
|
||||
test case classes includes methods for initializing and cleaning up of the
|
||||
test environment.
|
||||
|
||||
* Test-Proto.py: This is a prototype Test Case file. The file defines all
|
||||
the acceptable elements and their uses. Typically, one must copy this file
|
||||
and edit it for writing Test Cases.
|
||||
|
||||
* exc: This package contains custom exception classes used in this test
|
||||
suite.
|
||||
|
||||
* conf: This package contains the configuration classes for servers to be
|
||||
configured with.
|
||||
|
||||
* misc: This package contains several helper modules used in this test
|
||||
suite.
|
||||
- colour_terminal.py: A custom module for printing coloured output to
|
||||
the terminal. Currently it only supports 4 colours in a *nix
|
||||
environment.
|
||||
- wget_file.py: Module which contains WgetFile, which is a file data
|
||||
container object.
|
||||
|
||||
Working:
|
||||
================================================================================
|
||||
|
||||
The Test Files are valid Python scripts and the default mask for them is 755.
|
||||
A singular Test must be invoked in the following manner:
|
||||
$ ./python3 <Name of Test File> OR
|
||||
$ ./<Name of Test File>
|
||||
The script will then initialize the various elements and pass them to an object
|
||||
of the respective Test Class. A directory with the name <Test name>-test will be
|
||||
created and the PWD will be changed to this directory. The server is then
|
||||
spawned with the required configuration elements. A blocking call to Wget is
|
||||
made with the command line arguments specified in the Test Case along with the
|
||||
list of URLs that it must download. The server is killed once Wget returns and
|
||||
the following checks are used to determine the pass/fail status of the test:
|
||||
* Return Code: The Exit code of Wget is matched against the expected Exit
|
||||
Code as mentioned in the Test Case File.
|
||||
* Downloaded Files: Check whether the expected downloaded files exist on
|
||||
disk.
|
||||
* File Content: Test whether the file contents were correctly downloaded by
|
||||
Wget and not corrupted mid-way.
|
||||
* Excess Files: Check to see whether any unexpected files were downloaded
|
||||
by Wget.
|
||||
|
||||
Exit Codes:
|
||||
===============================================================================
|
||||
|
||||
Following is a list of Exit Status Codes for the tests:
|
||||
* 0 Test Successful
|
||||
* 66 Errors/Warnings Reported by Thread Sanitizer (If built with -fsanitize)
|
||||
* 77 Test Skipped
|
||||
* 99 Hard Error
|
||||
* 100 Test Failed
|
||||
|
||||
Tests are skipped when they are either not supported by the platform, or Wget
|
||||
is not compiled with support for that feature. This feature has not yet been
|
||||
implemented.
|
||||
|
||||
Hard Errors occur when there are problems with the Environment code. Hard
|
||||
Error reporting is currently not enabled and all errors are reported as
|
||||
failures.
|
||||
|
||||
All exceptions should ideally be handled gracefully. If you see any unhandled
|
||||
exceptions, please file a bug report at <bug-wget@gnu.org>
|
||||
|
||||
Environment Variables:
|
||||
================================================================================
|
||||
|
||||
* SERVER_WAIT: Set this environment variable with a value for the number of
|
||||
seconds the test should sleep between invoking the server and calling the Wget
|
||||
executable. This is used when one would like to test a different version of
|
||||
the executable or for running the test through external utilities like gdb and
|
||||
valgrind.
|
||||
* NO_CLEANUP: Do not remove the temporary files created by the test.
|
||||
This will prevent the ${testname}-test directory from being deleted
|
||||
* VALGRIND_TESTS: If this variable is set, the test suite will execute all the
|
||||
tests through valgrind's memcheck tool.
|
||||
|
||||
|
||||
File Structure:
|
||||
================================================================================
|
||||
|
||||
The test case files are Python scripts. It is believed that Python is a simple
|
||||
yet elegant language and should be easy for everyone to comprehend. This test
|
||||
suite is written with the objective of making it easy to write new tests. The
|
||||
structure has been kept as intuitive as possible and should not require much
|
||||
effort to get accustomed to.
|
||||
|
||||
All Test Files MUST begin with the following Three Lines:
|
||||
#!/usr/bin/python3
|
||||
from sys import exit
|
||||
from WgetTest import {HTTPTest|FTPTest}
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
It is recommended that a small description of the Test Case is provided next.
|
||||
This would be very helpful to future contributors.
|
||||
Next, is the const variable, TEST_NAME that defines the name of the Test.
|
||||
|
||||
Each File in the Test must be represented as a WgetFile object. The WgetFile
|
||||
Class has the following prototype:
|
||||
WgetFile (str name, str contents, str timestamp, dict rules)
|
||||
None except name is a mandatory paramter, one may pass only those parameters
|
||||
that are required by the File object.
|
||||
|
||||
The timestamp string should be a valid Unix Timestamp as defined in RFC xxxx.
|
||||
The rules object is a dictionary element, with the key as the Rule Name and
|
||||
value as the Rule Data. In most cases, the Rule Data is another dictionary.
|
||||
|
||||
Various variables used consistently across all tests are:
|
||||
* WGET_OPTIONS: The command line string passed to Wget upon invokation. This
|
||||
string may contain URLs, like in the case where in-URL authentication is
|
||||
used. Variable names passed like {{var_name}} will be replaced by the
|
||||
contents of the variable self.var_name before being passed to Wget
|
||||
* WGET_URLS: This is a list of filenames which will be appended as the URLs
|
||||
to Wget during invokation. This is a list of lists, where WGET_URLS[0]
|
||||
represents the list of Filenames called from Server[0], WGET_URLS[1] is a
|
||||
list of files downloaded from Server[2], etc.
|
||||
* Files: This variable defines the files that exist in the Server's
|
||||
filesystem. The Files variable is a list of lists of WgetFile objects.
|
||||
This means that File[0] is a list of WgetFile objects that lie on Server[0],
|
||||
File[1] a list of files on Server[1] and so on.
|
||||
* Existing_Files: This is a list of files that already exist in the
|
||||
directory from which Wget is invoked.
|
||||
* ExpectedReturnCode: The Exit Code expected to be returned by Wget after
|
||||
the test.
|
||||
* ExpectedDownloadedFiles: A list of files that are expected in the local
|
||||
directory after Wget has finished executing. This does not include the files
|
||||
already existing before Wget was launched and must be mentioned again.
|
||||
* Request_List: An unordered list of Requests that each server must receive.
|
||||
This too is a list of lists and follows the same convention as others above.
|
||||
|
||||
Both, the HTTPTest and FTPTest modules have the same prototype:
|
||||
{
|
||||
name,
|
||||
pre_hook,
|
||||
test_options,
|
||||
post_hook,
|
||||
protocols
|
||||
}
|
||||
name should be a string, and is usually passed to the TEST_NAME variable,
|
||||
the three hooks should be Python dict objects and protocols should be a list of
|
||||
protocols, like [HTTP, HTTPS].
|
||||
|
||||
Valid File Rules:
|
||||
================================================================================
|
||||
|
||||
This section lists the currently supported File Rules and their structure.
|
||||
|
||||
* Authentication: Used when a File must require Authorization for access.
|
||||
The value for this key is the following dictionary:
|
||||
|-->Type : Basic|Digest|Both|Both_inline
|
||||
|-->User : <Username>
|
||||
--->Pass : <Password>
|
||||
|
||||
* ExpectHeader : The following Headers MUST exist in every Request for the
|
||||
File. The value for this key is a dictionary object where each header is
|
||||
represented as:
|
||||
|-->Header Name : <Header Data>
|
||||
|
||||
* RejectHeader : This list of Headers must NEVER occur in a request. It
|
||||
uses the same value format as ExpectHeader.
|
||||
|
||||
* SendHeader : This list of Headers will be sent in EVERY response to a
|
||||
request for the respective file. It follows the same value format as
|
||||
ExpectHeader.
|
||||
|
||||
* Response : The HTTP Response Code to send to a request for this File.
|
||||
The value is an Integer that represents a valid HTTP Response Code.
|
||||
|
||||
Pre Test Hooks:
|
||||
================================================================================
|
||||
|
||||
The Pre-Test Hooks are executed just after starting the server and just before
|
||||
spawning an instance of the server. These are usually used for setting up the
|
||||
Test Environment and Server Rules. The currently supported Pre-Test Hooks are:
|
||||
|
||||
* ServerFiles : A list of WgetFile objects that must exist on the Server
|
||||
* LocalFiles : A list of WgetFile objects that exist locally on disk
|
||||
before Wget is executed.
|
||||
|
||||
Since pre_test is a dictionary, one may not assume that the hooks will be
|
||||
executed in the same order as they are defined.
|
||||
|
||||
Test Options:
|
||||
================================================================================
|
||||
|
||||
The test_options dictionary defines the commands to be used when the Test is
|
||||
executed. The currently supported options are:
|
||||
|
||||
* Urls : A list of the filenames that Wget must attempt to
|
||||
download. The complete URL will be created and passed to Wget
|
||||
automatically. (alias URLs)
|
||||
* WgetCommands : A string consisting of the various commandline switches
|
||||
sent to Wget upon invokation. Any data placed between {{ }} in this string
|
||||
will be replaced with the contents of self.<data> before being passed to
|
||||
Wget. This is particularly useful for getting the hostname and port for a
|
||||
file. While all Download URL's are passed to Urls, a notable exception is
|
||||
when in-url authentication is used. In such a case, the URL is specified in
|
||||
the WgetCommands string.
|
||||
|
||||
Post-Test Hooks:
|
||||
================================================================================
|
||||
|
||||
These hooks are executed as soon as the call to Wget returns. The post-test
|
||||
hooks are usually used to run checks on the data, files downloaded, return code,
|
||||
etc. The following hooks are currently supported:
|
||||
|
||||
* ExpectedRetcode : This is an integer value of the ReturnCode with which
|
||||
Wget is expected to exit. (alias ExpectedRetCode)
|
||||
* ExpectedFiles : This is a list of WgetFile objects of the files that
|
||||
must exist locally on disk in the Test directory.
|
||||
* FilesCrawled : This requires a list of the Requests that the server is
|
||||
expected to receive. The order is un-important since it will vary on the
|
||||
parallel-wget branch. This hook is used in tests for Recursive mode to
|
||||
ensure that the website is traversed correctly.
|
||||
|
||||
Writing New Tests:
|
||||
================================================================================
|
||||
|
||||
See Test-Proto.py for an example of how to write Test Case files. The
|
||||
recommended method for writing new Test Case files is to copy Test-Proto.py and
|
||||
modify it to ones needs.
|
||||
|
||||
In case you require any functionality that is not currently defined in List of
|
||||
Rules defined above, you should implement a new class in the conf package. The
|
||||
file name doesn't matter (though it's better to give it an appropriate name).
|
||||
The new rule or hook class should be like this:
|
||||
============================================
|
||||
from conf import rule
|
||||
|
||||
|
||||
@rule()
|
||||
class MyNewRule:
|
||||
def __init__(self, rule_arg):
|
||||
self.rule_arg = rule_arg
|
||||
# your rule initialization code goes here
|
||||
============================================
|
||||
from conf import hook
|
||||
|
||||
|
||||
@hook()
|
||||
class MyNewHook:
|
||||
def __init__(self, hook_arg):
|
||||
self.hook_arg = hook_arg
|
||||
# your hook initialization code goes here
|
||||
|
||||
def __call__(self, test_obj):
|
||||
# your hook code goes here
|
||||
============================================
|
||||
|
||||
Once a new Test File is created, it must be added to the TESTS variable in
|
||||
Makefile.am. This way the Test will be executed on running a 'make check'.
|
||||
If a Test is expected to fail on the current master branch, then the Test should
|
||||
also be added to the XFAIL_TESTS variable. This will allow expected failures to
|
||||
pass through. If a test mentioned in the XFAIL_TESTS variable passes, it gets
|
||||
red-flagged as a XPASS. Currently, tests expected to fail under valgrind are not
|
||||
explicitly marked as XFAIL. Tests failing under valgrind must always be
|
||||
considered a blocking error.
|
||||
|
||||
Remember to always name the Test correctly using the TEST_NAME variable. This
|
||||
is essential since a directory with the Test Name is created and this can
|
||||
cause synchronization problems when the Parallel Test Harness is used.
|
||||
One can use the following command on Unix systems to check for TEST_NAME
|
||||
clashes:
|
||||
$ grep -r -h "TEST_NAME =" | cut -c13- | uniq -c -d
|
||||
|
||||
Work Remaining:
|
||||
================================================================================
|
||||
|
||||
Some amount of work still remains to be done.
|
||||
* Errors in server-side checks need to be handled more explicitly
|
||||
* Support parallel-wget branch
|
||||
* Support to spawn multiple servers is already in place. Need to handle
|
||||
multiple requests to a server simultaneously. Use THreading MixIn.
|
||||
* SSL Tests. Use xyne's HTTPS server implemention
|
||||
* Complete support for FTP Tests
|
||||
* IRI Support. This shouldn't require much effort
|
||||
|
||||
Requirements:
|
||||
================================================================================
|
||||
|
||||
1. Python >= 3.0
|
||||
2. Automake >= 1.11
|
||||
53
testenv/Test--https.py
Executable file
53
testenv/Test--https.py
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from test.base_test import HTTP, HTTPS
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
"""
|
||||
This test ensures that Wget can download files from HTTPS Servers
|
||||
"""
|
||||
TEST_NAME = "HTTPS Downloads"
|
||||
############# File Definitions ###############################################
|
||||
File1 = "Would you like some Tea?"
|
||||
File2 = "With lemon or cream?"
|
||||
File3 = "Sure you're joking Mr. Feynman"
|
||||
|
||||
A_File = WgetFile ("File1", File1)
|
||||
B_File = WgetFile ("File2", File2)
|
||||
C_File = WgetFile ("File3", File3)
|
||||
|
||||
WGET_OPTIONS = "--no-check-certificate"
|
||||
WGET_URLS = [["File1", "File2"]]
|
||||
|
||||
Files = [[A_File, B_File]]
|
||||
Existing_Files = [C_File]
|
||||
|
||||
Servers = [HTTPS]
|
||||
|
||||
ExpectedReturnCode = 0
|
||||
ExpectedDownloadedFiles = [A_File, B_File, C_File]
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files,
|
||||
"LocalFiles" : Existing_Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedFiles" : ExpectedDownloadedFiles,
|
||||
"ExpectedRetcode" : ExpectedReturnCode
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test,
|
||||
protocols=Servers
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
106
testenv/Test--spider-r.py
Executable file
106
testenv/Test--spider-r.py
Executable file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
"""
|
||||
This test executed Wget in Spider mode with recursive retrieval.
|
||||
"""
|
||||
TEST_NAME = "Recursive Spider"
|
||||
############# File Definitions ###############################################
|
||||
mainpage = """
|
||||
<html>
|
||||
<head>
|
||||
<title>Main Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Some text and a link to a <a href="http://127.0.0.1:{{port}}/secondpage.html">second page</a>.
|
||||
Also, a <a href="http://127.0.0.1:{{port}}/nonexistent">broken link</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
secondpage = """
|
||||
<html>
|
||||
<head>
|
||||
<title>Second Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Some text and a link to a <a href="http://127.0.0.1:{{port}}/thirdpage.html">third page</a>.
|
||||
Also, a <a href="http://127.0.0.1:{{port}}/nonexistent">broken link</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
thirdpage = """
|
||||
<html>
|
||||
<head>
|
||||
<title>Third Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Some text and a link to a <a href="http://127.0.0.1:{{port}}/dummy.txt">text file</a>.
|
||||
Also, another <a href="http://127.0.0.1:{{port}}/againnonexistent">broken link</a>.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
dummyfile = "Don't care."
|
||||
|
||||
|
||||
index_html = WgetFile ("index.html", mainpage)
|
||||
secondpage_html = WgetFile ("secondpage.html", secondpage)
|
||||
thirdpage_html = WgetFile ("thirdpage.html", thirdpage)
|
||||
dummy_txt = WgetFile ("dummy.txt", dummyfile)
|
||||
|
||||
Request_List = [
|
||||
[
|
||||
"HEAD /",
|
||||
"GET /",
|
||||
"GET /robots.txt",
|
||||
"HEAD /secondpage.html",
|
||||
"GET /secondpage.html",
|
||||
"HEAD /nonexistent",
|
||||
"HEAD /thirdpage.html",
|
||||
"GET /thirdpage.html",
|
||||
"HEAD /dummy.txt",
|
||||
"HEAD /againnonexistent"
|
||||
]
|
||||
]
|
||||
|
||||
WGET_OPTIONS = "--spider -r"
|
||||
WGET_URLS = [[""]]
|
||||
|
||||
Files = [[index_html, secondpage_html, thirdpage_html, dummy_txt]]
|
||||
|
||||
ExpectedReturnCode = 8
|
||||
ExpectedDownloadedFiles = []
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedFiles" : ExpectedDownloadedFiles,
|
||||
"ExpectedRetcode" : ExpectedReturnCode,
|
||||
"FilesCrawled" : Request_List
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
53
testenv/Test-Content-disposition-2.py
Executable file
53
testenv/Test-Content-disposition-2.py
Executable file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
"""
|
||||
This test ensures that Wget parses the Content-Disposition header
|
||||
correctly and creates the appropriate file when the said filename exists.
|
||||
"""
|
||||
TEST_NAME = "Content Disposition Clobber"
|
||||
############# File Definitions ###############################################
|
||||
File1 = "Teapot"
|
||||
File2 = "The Teapot Protocol"
|
||||
|
||||
File2_rules = {
|
||||
"SendHeader" : {
|
||||
"Content-Disposition" : "Attachment; filename=HTTP.Teapot"
|
||||
}
|
||||
}
|
||||
A_File = WgetFile ("HTTP.Teapot", File1)
|
||||
B_File = WgetFile ("File2", File2, rules=File2_rules)
|
||||
|
||||
WGET_OPTIONS = "--content-disposition"
|
||||
WGET_URLS = [["File2"]]
|
||||
|
||||
Files = [[B_File]]
|
||||
Existing_Files = [A_File]
|
||||
|
||||
ExpectedReturnCode = 0
|
||||
ExpectedDownloadedFiles = [WgetFile ("HTTP.Teapot.1", File2), A_File]
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files,
|
||||
"LocalFiles" : Existing_Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedFiles" : ExpectedDownloadedFiles,
|
||||
"ExpectedRetcode" : ExpectedReturnCode
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
56
testenv/Test-Content-disposition.py
Executable file
56
testenv/Test-Content-disposition.py
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
"""
|
||||
This test ensures that Wget parses the Content-Disposition header
|
||||
correctly and creates a local file accordingly.
|
||||
"""
|
||||
TEST_NAME = "Content Disposition Header"
|
||||
############# File Definitions ###############################################
|
||||
File1 = """All that is gold does not glitter,
|
||||
Not all those who wander are lost;
|
||||
The old that is strong does not wither,
|
||||
Deep roots are not reached by the frost.
|
||||
From the ashes a fire shall be woken,
|
||||
A light from the shadows shall spring;
|
||||
Renewed shall be blade that was broken,
|
||||
The crownless again shall be king."""
|
||||
|
||||
File1_rules = {
|
||||
"SendHeader" : {
|
||||
"Content-Disposition" : "Attachment; filename=JRR.Tolkein"
|
||||
}
|
||||
}
|
||||
A_File = WgetFile ("LOTR", File1, rules=File1_rules)
|
||||
|
||||
WGET_OPTIONS = "--content-disposition"
|
||||
WGET_URLS = [["LOTR"]]
|
||||
|
||||
Files = [[A_File]]
|
||||
|
||||
ExpectedReturnCode = 0
|
||||
ExpectedDownloadedFiles = [WgetFile ("JRR.Tolkein", File1)]
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedFiles" : ExpectedDownloadedFiles,
|
||||
"ExpectedRetcode" : ExpectedReturnCode
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user