mirror of
https://github.com/mirror/wget.git
synced 2026-08-21 02:13:27 +08:00
Compare commits
375 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d94d9cd98b | ||
|
|
882ed28d59 | ||
|
|
e316d253fa | ||
|
|
9dde436dd6 | ||
|
|
bf868e8840 | ||
|
|
5352eac8fa | ||
|
|
d419cd7c0c | ||
|
|
33c5d979ce | ||
|
|
9df2250f4c | ||
|
|
3d8e765c1d | ||
|
|
c83f344564 | ||
|
|
07a350d30c | ||
|
|
875d0819c4 | ||
|
|
b25fbe5afc | ||
|
|
4e8e159289 | ||
|
|
8705e27e20 | ||
|
|
a7e9a05a89 | ||
|
|
87f4fee8c9 | ||
|
|
5e3a760731 | ||
|
|
01d5177f7a | ||
|
|
103cbf1751 | ||
|
|
6f62bc5cd8 | ||
|
|
f6b28575cc | ||
|
|
5de8ab2a0b | ||
|
|
a8d437d827 | ||
|
|
fc336758ab | ||
|
|
9ee2fdd50d | ||
|
|
cfe7589397 | ||
|
|
15f18e7606 | ||
|
|
ee196f6fe5 | ||
|
|
0417ef8b50 | ||
|
|
56c0098063 | ||
|
|
712d607f9b | ||
|
|
32499e717d | ||
|
|
b147fb1638 | ||
|
|
365aeba704 | ||
|
|
b0893e84b3 | ||
|
|
f0de37cc27 | ||
|
|
05d73a926a | ||
|
|
ec5e0f421c | ||
|
|
0d9615292e | ||
|
|
6bc2620592 | ||
|
|
b0b1cde6e2 | ||
|
|
f37dd1aa2d | ||
|
|
b5778699f0 | ||
|
|
b8c567a3ef | ||
|
|
425368c602 | ||
|
|
1ca88a4208 | ||
|
|
26790c3583 | ||
|
|
fcd3b3c473 | ||
|
|
eb0789d43f | ||
|
|
ab2d5d83d2 | ||
|
|
cbaabe78e8 | ||
|
|
0a4826f4a1 | ||
|
|
71425f1bb3 | ||
|
|
f59dac3023 | ||
|
|
8b50cd4b61 | ||
|
|
a80986a8c9 | ||
|
|
94447e31a6 | ||
|
|
e6713474c0 | ||
|
|
aaefe8bc83 | ||
|
|
4b845615fa | ||
|
|
aeca2c33c0 | ||
|
|
11c6dcb705 | ||
|
|
ce088c2b9e | ||
|
|
d9ab65abd2 | ||
|
|
e4583ab364 | ||
|
|
4850e9c873 | ||
|
|
d9325f5db5 | ||
|
|
5d3b52d0b8 | ||
|
|
e194c1dfd3 | ||
|
|
3e609a1192 | ||
|
|
5edc97f3f8 | ||
|
|
007bee88d8 | ||
|
|
d87fdecd55 | ||
|
|
f0e7326c20 | ||
|
|
54227091b8 | ||
|
|
1853e425f5 | ||
|
|
fe0bfb5ee9 | ||
|
|
255133326b | ||
|
|
0c18773308 | ||
|
|
9217b864d8 | ||
|
|
5e2ecaf277 | ||
|
|
cd23c7fe0e | ||
|
|
ed996fe32f | ||
|
|
1b8e54b808 | ||
|
|
eab0f5d222 | ||
|
|
e94a542d0f | ||
|
|
b6de436547 | ||
|
|
c6b750061a | ||
|
|
b41a3a6568 | ||
|
|
f687547d6e | ||
|
|
841efb0108 | ||
|
|
09d47ead18 | ||
|
|
00203b2888 | ||
|
|
1553c70961 | ||
|
|
bc75d2ecdf | ||
|
|
e15ef0b4da | ||
|
|
b19d8032c2 | ||
|
|
3c51ad7f02 | ||
|
|
6a9b2d36e1 | ||
|
|
40f3613b67 | ||
|
|
acc76b1e02 | ||
|
|
e4be5e3b9a | ||
|
|
bfbc2866c5 | ||
|
|
d9f21b4b95 | ||
|
|
7b43510fe3 | ||
|
|
1356e90a14 | ||
|
|
f9646a0c14 | ||
|
|
1ce1a40f94 | ||
|
|
7a7a241e5b | ||
|
|
18fe274e1c | ||
|
|
c6ee033425 | ||
|
|
0c1bff841b | ||
|
|
f518d6cea1 | ||
|
|
50ec4d9c3d | ||
|
|
94b8458af1 | ||
|
|
db621341a4 | ||
|
|
2ece0cc425 | ||
|
|
0ae74cde39 | ||
|
|
2bac75dbc5 | ||
|
|
6ab8659ff5 | ||
|
|
bd8893a76c | ||
|
|
6c989c7131 | ||
|
|
425584b61e | ||
|
|
ff6fc1f8dd | ||
|
|
94805ad55a | ||
|
|
897ef07712 | ||
|
|
6e259b76b7 | ||
|
|
cf4991d602 | ||
|
|
176c2b17fc | ||
|
|
9823dc1989 | ||
|
|
2457715e7d | ||
|
|
a0c30fc72b | ||
|
|
e4a8fe84e2 | ||
|
|
170a469533 | ||
|
|
d81a8d5f56 | ||
|
|
831b9d1880 | ||
|
|
7259c30929 | ||
|
|
b6d8e1e707 | ||
|
|
43e5f022e2 | ||
|
|
51415ad5d6 | ||
|
|
e0f149d29d | ||
|
|
375b671f01 | ||
|
|
981c7456ff | ||
|
|
5e71d5aea1 | ||
|
|
c6300a3ac7 | ||
|
|
2303793a62 | ||
|
|
e52879514f | ||
|
|
fdd8b8c997 | ||
|
|
35bfcb34b0 | ||
|
|
8078adee7f | ||
|
|
9f83e0e13c | ||
|
|
f48be4e0c6 | ||
|
|
5ae5d2eaeb | ||
|
|
47d0d4c331 | ||
|
|
d272339fda | ||
|
|
297d040ce1 | ||
|
|
ea97693b54 | ||
|
|
fb8f81040a | ||
|
|
4ea40809cb | ||
|
|
64a3d521de | ||
|
|
c2bb6bc875 | ||
|
|
a5c6ae8f28 | ||
|
|
42333c4a5e | ||
|
|
a6c2ba73d9 | ||
|
|
9dd6ea7481 | ||
|
|
c81e3df2bc | ||
|
|
148065bc00 | ||
|
|
4152e98bb0 | ||
|
|
3e2c95b0dd | ||
|
|
605d9053e5 | ||
|
|
6092205538 | ||
|
|
9c34d4ed09 | ||
|
|
3eff3ad69a | ||
|
|
56a02c1a44 | ||
|
|
e5cb0f77e6 | ||
|
|
3697fd9451 | ||
|
|
b4440d96cf | ||
|
|
69c45cba43 | ||
|
|
18b0979357 | ||
|
|
c986ea790c | ||
|
|
3e3073ca7b | ||
|
|
796da8da3a | ||
|
|
7cd528a4e9 | ||
|
|
601b282cd8 | ||
|
|
bc347cc36f | ||
|
|
6fc11e46ec | ||
|
|
ff876a3710 | ||
|
|
21fc7546ef | ||
|
|
afbcaaecba | ||
|
|
b64fa2eb84 | ||
|
|
8c2d9afd08 | ||
|
|
b36c3e48c4 | ||
|
|
efe090df89 | ||
|
|
f8e9a64ec7 | ||
|
|
5753ed4a72 | ||
|
|
03f8babefe | ||
|
|
3858500de4 | ||
|
|
e29020e10c | ||
|
|
be78cba9e5 | ||
|
|
6cb857502f | ||
|
|
65fc59aefa | ||
|
|
8b83306d54 | ||
|
|
b89cda0a77 | ||
|
|
0606f1a133 | ||
|
|
c443399ab1 | ||
|
|
7cbe8141d1 | ||
|
|
eab853b7e6 | ||
|
|
3d7797c46e | ||
|
|
cae32d41c1 | ||
|
|
a44841cbe2 | ||
|
|
e43ae39dff | ||
|
|
c5f2c7fcef | ||
|
|
550cd6e9d2 | ||
|
|
97ce41b2d0 | ||
|
|
416d0e892c | ||
|
|
e2c8436e17 | ||
|
|
ebda24eb69 | ||
|
|
582e5d8ef7 | ||
|
|
601401da71 | ||
|
|
f3289f76ec | ||
|
|
26787225c1 | ||
|
|
104fd20ac3 | ||
|
|
ca402e2f81 | ||
|
|
8445279306 | ||
|
|
bb025955c3 | ||
|
|
08cedb953b | ||
|
|
c03855be40 | ||
|
|
3e8f9a6436 | ||
|
|
5a712b5bcf | ||
|
|
964ba0a0d5 | ||
|
|
ffccc7d3be | ||
|
|
d1ab00cab4 | ||
|
|
dd1b69c600 | ||
|
|
3b502901c0 | ||
|
|
a22cd7394b | ||
|
|
8a83a9d893 | ||
|
|
8e6de1fb5f | ||
|
|
8a919932a6 | ||
|
|
087e17be1c | ||
|
|
ee5b28367c | ||
|
|
4d77b190fd | ||
|
|
854ebbf4dd | ||
|
|
8624553a31 | ||
|
|
4eeabffee6 | ||
|
|
f2b9004e8f | ||
|
|
38a7829dcb | ||
|
|
351e438e51 | ||
|
|
6d4158122c | ||
|
|
8c2fd06ba8 | ||
|
|
67a4c6cf97 | ||
|
|
848d7537e1 | ||
|
|
6c572cbc33 | ||
|
|
97787110a2 | ||
|
|
226785838a | ||
|
|
320cfdcb65 | ||
|
|
d7ea21b2e7 | ||
|
|
c9bc854938 | ||
|
|
ed54c64ad2 | ||
|
|
701e407af5 | ||
|
|
dfa1f4e064 | ||
|
|
43c89ab7a5 | ||
|
|
5bb2f43165 | ||
|
|
605eafa792 | ||
|
|
d68295bdb1 | ||
|
|
59080465d1 | ||
|
|
b65b9cb8c5 | ||
|
|
593b59c697 | ||
|
|
b9e5c3e8b3 | ||
|
|
87186cbc2f | ||
|
|
f694b2ea24 | ||
|
|
d260ded060 | ||
|
|
70f7cdf1af | ||
|
|
351d328c07 | ||
|
|
3b6a3e84a0 | ||
|
|
fb23bc0611 | ||
|
|
cb358c0a84 | ||
|
|
12218d353b | ||
|
|
3832728138 | ||
|
|
38933de17c | ||
|
|
aed7d4163a | ||
|
|
42c15e47b4 | ||
|
|
c3835a425a | ||
|
|
8b2954e58a | ||
|
|
bba67890f3 | ||
|
|
0c9fb2b041 | ||
|
|
fbd9b9c16b | ||
|
|
1fd32c995c | ||
|
|
c289349684 | ||
|
|
1dec2028d0 | ||
|
|
7e85e9509e | ||
|
|
85dd2f7ce2 | ||
|
|
e1fc2057c7 | ||
|
|
eaf2fc9a4f | ||
|
|
e505664ef3 | ||
|
|
e6123ed645 | ||
|
|
5137cff125 | ||
|
|
42c78fdd71 | ||
|
|
a7df7ecc2f | ||
|
|
695f11304b | ||
|
|
a12bd59111 | ||
|
|
ffb94036f2 | ||
|
|
92035dbabd | ||
|
|
c19d76c024 | ||
|
|
a300f1e47d | ||
|
|
72b2c58983 | ||
|
|
c52bbad9e4 | ||
|
|
44ba49b31f | ||
|
|
eee1589ef3 | ||
|
|
e9cc8b2f7c | ||
|
|
b8f036d16c | ||
|
|
91f0f99e9a | ||
|
|
c78caecbb4 | ||
|
|
8760123cee | ||
|
|
c9c0e4c641 | ||
|
|
9e0d87a248 | ||
|
|
6a2d67b583 | ||
|
|
49f6d0ded8 | ||
|
|
4df7703d62 | ||
|
|
7f43748544 | ||
|
|
9d35f87218 | ||
|
|
90896e3314 | ||
|
|
5ce9389384 | ||
|
|
099d8ee3da | ||
|
|
e976d4f3dc | ||
|
|
ccd369d5f2 | ||
|
|
027d9f385d | ||
|
|
83837b0606 | ||
|
|
ae80fd2ec7 | ||
|
|
277785fa2a | ||
|
|
52dd6da6e0 | ||
|
|
550457bcad | ||
|
|
8dc52c6eaa | ||
|
|
54fd8de415 | ||
|
|
81409cb9c8 | ||
|
|
0e6f1c2dac | ||
|
|
7df4b05f0b | ||
|
|
bc2891f307 | ||
|
|
6c30653a1a | ||
|
|
edbeaa0c4e | ||
|
|
e3b3ea5120 | ||
|
|
50238e49b9 | ||
|
|
6443581d72 | ||
|
|
3be7e0a53c | ||
|
|
b56a528aea | ||
|
|
dcf667fb57 | ||
|
|
a2c0835007 | ||
|
|
3ebbd84518 | ||
|
|
b60ff61b75 | ||
|
|
2c1e0326a3 | ||
|
|
359dd16760 | ||
|
|
1e229375aa | ||
|
|
4f09a3118f | ||
|
|
b1838bdfd1 | ||
|
|
98f843f3cc | ||
|
|
9e8d899a35 | ||
|
|
5dcb116087 | ||
|
|
242ddfc74e | ||
|
|
13c6e7832a | ||
|
|
22bd8011e8 | ||
|
|
fe401688a6 | ||
|
|
6e4c3ab999 | ||
|
|
022dbcb343 | ||
|
|
7c0270cdb5 | ||
|
|
67e6027ea1 | ||
|
|
e9845d2813 | ||
|
|
959e5d1e90 | ||
|
|
74f6cb8884 | ||
|
|
e2cb2fa2e3 | ||
|
|
b718128b4f | ||
|
|
798f554773 | ||
|
|
06fc1edb54 | ||
|
|
85b98d0834 | ||
|
|
4759cf099f |
93
.gitignore
vendored
Normal file
93
.gitignore
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
# 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
|
||||
tests/*.log
|
||||
tests/*.trs
|
||||
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
|
||||
po/stamp-po
|
||||
# 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/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
|
||||
21536
ChangeLog-2014-12-10
Normal file
21536
ChangeLog-2014-12-10
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
Please note that Wget has more than one ChangeLog file:
|
||||
|
||||
./ChangeLog: documents changes to files in the top-level directory
|
||||
and to files in subdirectories like po/ that don't have
|
||||
their own ChangeLogs
|
||||
|
||||
src/ChangeLog: documents only changes to files in the src directory
|
||||
|
||||
doc/ChangeLog: documents only changes to files in the doc directory
|
||||
|
||||
windows/ChangeLog: documents only changes to files in the windows directory
|
||||
|
||||
msdos/ChangeLog: documents only changes to files in the msdos directory
|
||||
|
||||
When checking to see if a patch you sent in has been applied, please
|
||||
look in the appropriate ChangeLog(s).
|
||||
@@ -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'.
|
||||
|
||||
|
||||
23
Makefile.am
23
Makefile.am
@@ -41,10 +41,10 @@ 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 \
|
||||
EXTRA_DIST = MAILING-LIST \
|
||||
msdos/config.h msdos/Makefile.DJ \
|
||||
msdos/Makefile.WC ABOUT-NLS \
|
||||
build-aux/build_info.pl build-aux/git-version-gen .version
|
||||
|
||||
@@ -60,5 +60,20 @@ clean-generic:
|
||||
|
||||
# Arrange so that .tarball-version appears only in the distribution
|
||||
# tarball, and never in a checked-out repository.
|
||||
dist-hook:
|
||||
dist-hook: gen-ChangeLog
|
||||
$(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version
|
||||
|
||||
gen_start_date = 2014-12-10
|
||||
.PHONY: gen-ChangeLog
|
||||
gen-ChangeLog:
|
||||
$(AM_V_GEN)if test -d .git; then \
|
||||
log_fix="$(srcdir)/build-aux/git-log-fix"; \
|
||||
test -e "$$log_fix" \
|
||||
|| amend_git_log=; \
|
||||
$(top_srcdir)/build-aux/gitlog-to-changelog \
|
||||
$$amend_git_log --since=$(gen_start_date) > $(distdir)/cl-t && \
|
||||
echo >> $(distdir)/cl-t && \
|
||||
cat ChangeLog-2014-12-10 >> $(distdir)/cl-t && \
|
||||
{ rm -f $(distdir)/ChangeLog && \
|
||||
mv $(distdir)/cl-t $(distdir)/ChangeLog; } \
|
||||
fi
|
||||
|
||||
160
NEWS
160
NEWS
@@ -1,11 +1,103 @@
|
||||
GNU Wget NEWS -- history of user-visible changes.
|
||||
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||
2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
|
||||
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software
|
||||
Foundation, Inc.
|
||||
See the end for copying conditions.
|
||||
|
||||
Please send GNU Wget bug reports to <bug-wget@gnu.org>.
|
||||
|
||||
|
||||
* Changes in Wget 1.16.3
|
||||
|
||||
** Fix a regression introduced by wget 1.16.2 that --quiet is not
|
||||
really quiet anymore.
|
||||
|
||||
* Changes in Wget 1.16.2
|
||||
|
||||
** Native uuid generation on Windows
|
||||
|
||||
** Fix build on Solaris
|
||||
|
||||
** Allow progress bar on stderr when -o is used
|
||||
|
||||
** Accept 5-digit port numbers in FTP EPSV responses.
|
||||
|
||||
** Support older versions of flex.
|
||||
|
||||
** Updated translations.
|
||||
|
||||
* Changes in Wget 1.16.1
|
||||
|
||||
** Add --enable-assert configure option.
|
||||
|
||||
** Use pkg-config to check for libraries presence.
|
||||
|
||||
** Do not limit --secure-protocol=auto|pfs to TLSv1.0.
|
||||
|
||||
** Add --secure-protocol=TLSv1_1|TLSv1_2 .
|
||||
|
||||
** Full C89 source code compliance.
|
||||
|
||||
** Select and use the most secure authentication scheme with HTTP connections.
|
||||
|
||||
** Fix issues with turkish locales.
|
||||
|
||||
** Handle 504 Gateway Timeout.
|
||||
|
||||
** New option --crl-file to load Certificate Revocation Lists.
|
||||
|
||||
** Add valgrind support to tests suite.
|
||||
|
||||
** Fix an off-by-one problem in the progress bar (introduced in 1.16).
|
||||
|
||||
* Changes in Wget 1.16
|
||||
|
||||
** No longer create local symbolic links by default. Closes CVE-2014-4877.
|
||||
|
||||
** Use libpsl for verifying cookie domains.
|
||||
|
||||
** Default progress bar output changed.
|
||||
|
||||
** Introduce --show-progress to force display the progress bar.
|
||||
|
||||
** Introduce --no-config. The wgetrc files will not be read.
|
||||
|
||||
** 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
|
||||
@@ -32,7 +124,7 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
|
||||
** The GNU TLS backend honors correctly the timeout value.
|
||||
|
||||
** Add support for RFC 2617 Digest Access Authentication.
|
||||
|
||||
|
||||
* Changes in Wget 1.13.4
|
||||
|
||||
** Now --version and --help work again.
|
||||
@@ -45,7 +137,7 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
|
||||
is specified.
|
||||
|
||||
** Fix a segfault on an incomplete STYLE tag.
|
||||
|
||||
|
||||
* Changes in Wget 1.13.3
|
||||
|
||||
** Support HTTP/1.1
|
||||
@@ -111,7 +203,7 @@ Please send GNU Wget bug reports to <bug-wget@gnu.org>.
|
||||
|
||||
** Introduce `show_all_dns_entries' to print all IP addresses corresponding to
|
||||
a DNS name when it is resolved.
|
||||
|
||||
|
||||
* Changes in Wget 1.12
|
||||
|
||||
** Mailing list MOVED to bug-wget@gnu.org
|
||||
@@ -165,7 +257,7 @@ forces the percent-encoding of all non-ASCII bytes
|
||||
now documented: save_headers, spider, and user_agent,
|
||||
auth_no_challenge, and keep_session_cookies. Also added documentation
|
||||
for the "lowercase" and "uppercase" values for --restrict-file-names, which had been present since Wget 1.11.
|
||||
|
||||
|
||||
* Changes in Wget 1.11.4
|
||||
|
||||
** Fixed an issue (apparently a regression) where -O would refuse to
|
||||
@@ -179,13 +271,13 @@ locally with content.
|
||||
to a pointer-to-time_t.
|
||||
|
||||
** Translation updates for Catalan.
|
||||
|
||||
|
||||
* Changes in Wget 1.11.3
|
||||
|
||||
** Downgraded -N with -O to a warning, rather than an error.
|
||||
|
||||
** Translation updates
|
||||
|
||||
|
||||
* Changes in Wget 1.11.2
|
||||
|
||||
** Fixed a problem in authenticating over HTTPS through a proxy.
|
||||
@@ -207,7 +299,7 @@ multiple times. This has been fixed in 1.11.2.
|
||||
for improved conformance with RFC 3986. However, this behavior presents
|
||||
problems for some FTP setups, and so they are now preserved again, for
|
||||
FTP URLs only.
|
||||
|
||||
|
||||
* Changes in Wget 1.11.1.
|
||||
|
||||
** Interrupted downloads no longer result in renaming the file
|
||||
@@ -229,7 +321,7 @@ be surprising, and notes that they may change in the future.
|
||||
|
||||
** Documentation of --no-parents now explains how a trailing slash, or
|
||||
lack thereof, in the specified URL, will affect behavior.
|
||||
|
||||
|
||||
* Changes in Wget 1.11.
|
||||
|
||||
** Timestamping now uses the value from the most recent HTTP response,
|
||||
@@ -275,7 +367,7 @@ available at http://hg.addictivecode.org/. Prior to this, the source
|
||||
code was hosted on Subversion (migrated from the original CVS); you can
|
||||
still get access to older tags and branches for Wget in the Subversion
|
||||
repository at http://addictivecode.org/svn/wget/.
|
||||
|
||||
|
||||
* Changes in Wget 1.10.
|
||||
|
||||
** Downloading files larger than 2GB, sometimes referred to as "large
|
||||
@@ -386,9 +478,9 @@ http_password and proxy_password respectively. The login and passwd
|
||||
.wgetrc commands have been deprecated.
|
||||
|
||||
* `wget -b' now works correctly under Windows.
|
||||
|
||||
|
||||
* Wget 1.9.1 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Wget 1.9.
|
||||
|
||||
** It is now possible to specify that POST method be used for HTTP
|
||||
@@ -440,11 +532,11 @@ values "yes" and "no" along with the traditional "on" and "off".
|
||||
** It is now possible to specify decimal values for timeouts, waiting
|
||||
periods, and download rate. For instance, `--wait=0.5' now works as
|
||||
expected, as does `--dns-timeout=0.5' and even `--limit-rate=2.5k'.
|
||||
|
||||
|
||||
* Wget 1.8.2 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Wget 1.8.1 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Wget 1.8.
|
||||
|
||||
** A new progress indicator is now available and used by default.
|
||||
@@ -504,9 +596,9 @@ no longer translated to `?', nor `%2B' to `+'. Unsafe characters
|
||||
which are not reserved are still escaped, of course.
|
||||
|
||||
** No more than 20 successive redirections are allowed.
|
||||
|
||||
|
||||
* Wget 1.7.1 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Wget 1.7.
|
||||
|
||||
** SSL (`https') pages now work if you compile Wget with SSL support;
|
||||
@@ -548,7 +640,7 @@ large sites (thousands of documents).
|
||||
documentation. (The last version that shipped with a man page was
|
||||
1.4.5). To get this, you need to have pod2man from the Perl
|
||||
distribution installed on your system.
|
||||
|
||||
|
||||
* Changes in Wget 1.6
|
||||
|
||||
** Administrative changes.
|
||||
@@ -599,13 +691,13 @@ passive_ftp is the only .wgetrc command which takes a lockable Boolean.
|
||||
bound to multiple IP addresses.
|
||||
|
||||
** wget now accepts (illegal per HTTP spec) relative URLs in HTTP redirects.
|
||||
|
||||
|
||||
* Wget 1.5.3 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Wget 1.5.2 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Wget 1.5.1 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Wget 1.5.0
|
||||
|
||||
** Wget speaks many languages!
|
||||
@@ -640,7 +732,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
|
||||
@@ -651,11 +743,11 @@ download.
|
||||
|
||||
** The manual page, now hopelessly out of date, is no longer
|
||||
distributed with Wget.
|
||||
|
||||
|
||||
* Wget 1.4.5 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Wget 1.4.4 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Wget 1.4.3
|
||||
|
||||
** Wget is now a GNU utility.
|
||||
@@ -671,7 +763,7 @@ distributed with Wget.
|
||||
** Global wgetrc now goes to /usr/local/etc (i.e. $sysconfdir).
|
||||
|
||||
** Lots of bugfixes.
|
||||
|
||||
|
||||
* Changes in Wget 1.4.2
|
||||
|
||||
** New mirror site at ftp://sunsite.auc.dk/pub/infosystems/wget/,
|
||||
@@ -689,7 +781,7 @@ files.
|
||||
** --convert-links should work now.
|
||||
|
||||
** Minor bugfixes.
|
||||
|
||||
|
||||
* Changes in Wget 1.4.1
|
||||
|
||||
** Minor bugfixes.
|
||||
@@ -697,7 +789,7 @@ files.
|
||||
** Added -I (the opposite of -X).
|
||||
|
||||
** Dot tracing is now customizable; try wget --dot-style=binary
|
||||
|
||||
|
||||
* Changes in Wget 1.4.0
|
||||
|
||||
** Wget 1.4.0 [formerly known as Geturl] is an extensive rewrite of
|
||||
@@ -778,7 +870,7 @@ turn on mirroring options).
|
||||
** Lots of small features I can't remember. :-)
|
||||
|
||||
** A host of bugfixes.
|
||||
|
||||
|
||||
* Changes in Geturl 1.3
|
||||
|
||||
** Added FTP globbing support (ftp://fly.cc.fer.hr/*)
|
||||
@@ -796,9 +888,9 @@ turn on mirroring options).
|
||||
** Added support for robots.txt
|
||||
|
||||
** Fixed some minor bugs
|
||||
|
||||
|
||||
* Geturl 1.2 is a bugfix release with no user-visible changes.
|
||||
|
||||
|
||||
* Changes in Geturl 1.1
|
||||
|
||||
** REST supported in FTP
|
||||
@@ -816,7 +908,7 @@ geturl -vo log http://fly.cc.fer.hr/
|
||||
** <base href="xxx"> supported
|
||||
|
||||
** autoconf supported
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Copyright information:
|
||||
|
||||
|
||||
135
README.checkout
135
README.checkout
@@ -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, GnuTLS, libidn,
|
||||
libiconv, libpsl, libpcre and pkg-config 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
|
||||
@@ -24,11 +24,11 @@ Compiling From Repository Sources
|
||||
tests in the tests/ sub directory. Tarball distributions include an
|
||||
already-generated wget.1 manual. The command "make check" runs the
|
||||
test suite written in perl. To execute all the tests you need
|
||||
[24]libwww-perl perl library. If "perl -MCPAN -e 'install
|
||||
Bundle::LWP'" fails then you most likely don't have cpan module
|
||||
installed. First download [25]CPAN and [26]install it. Then execute
|
||||
"perl -MCPAN -e 'install Bundle::LWP'". Now "make check" should
|
||||
pass most of the tests in the test suite.
|
||||
[24]libwww-perl and libio-socket-ssl-perl perl library. If
|
||||
"perl -MCPAN -e 'install Bundle::LWP'" fails then you most likely don't
|
||||
have cpan module installed. First download [25]CPAN and [26]install it.
|
||||
Then execute "perl -MCPAN -e 'install Bundle::LWP'".
|
||||
Now "make check" should pass most of the tests in the test suite.
|
||||
|
||||
* [27]texinfo in order to generate Info, PostScript and/or HTML
|
||||
documentation. You don't need texinfo in order to generate the
|
||||
@@ -46,32 +46,54 @@ Compiling From Repository Sources
|
||||
to export M4=<new m4 path>, to be sure that autoconf/automake use
|
||||
it instead of the old one.
|
||||
|
||||
* [29]OpenSSL to handle encrypted web sessions. You almost certainly
|
||||
want this. It is not enough to have the library installed; you need
|
||||
to have the header files available to compile against as well. For
|
||||
GNU/Linux systems, this usually means installing a "developer"
|
||||
package for openssl (for example, [30]Debian systems require
|
||||
installation of the libssl-dev package). Alternatively, you can
|
||||
compile GNU Wget against the [31]GNUTLS library instead, by
|
||||
specifying --with-ssl=gnutls to the ./configure script; however,
|
||||
building against GNUTLS is currently experimental, and not
|
||||
officially supported. If you have OpenSSL and its development
|
||||
headers installed, but don't want to build Wget with it, specify
|
||||
--without-ssl to the ./configure script.
|
||||
* [29]GnuTLS to allow encrypted data transfer (HTTPS).
|
||||
You need the header files and the library installed.
|
||||
As an alternative, you can use [30]OpenSSL by specifying
|
||||
--with-ssl=openssl to the ./configure script.
|
||||
If you do not want HTTPS support, specify --without-ssl to the
|
||||
./configure script.
|
||||
If you want to compile+link a non-system library version use
|
||||
--with-libgnutls-prefix (or if having pkg-config: see description
|
||||
below).
|
||||
|
||||
* [32]libidn is required for IDN/IRI support (non-ASCII characters
|
||||
* [30]OpenSSL to allow encrypted data transfer (HTTPS) an
|
||||
alternative to [31]GnuTLS.
|
||||
You need the header files and the library installed.
|
||||
If you want to compile+link a non-system library version use
|
||||
--with-libssl-prefix (or if having pkg-config: see description below).
|
||||
|
||||
* [31]libidn is required for IDN/IRI support (non-ASCII characters
|
||||
within what would otherwise be URLs).
|
||||
|
||||
* [33]libiconv is required on non-GNU systems, for IDN/IRI support.
|
||||
* [32]libiconv is required on non-GNU systems, for IDN/IRI support.
|
||||
On GNU systems, the functionality provided by libiconv is already
|
||||
present in the system libraries.
|
||||
|
||||
* [34]git is used to fetch gnulib files trough the bootstrap.sh script.
|
||||
* [33]git is used to fetch gnulib files trough the bootstrap.sh script.
|
||||
|
||||
* [34]libpsl is required for using a public suffix list to check for valid
|
||||
cookie domains. You need the header files and the library installed.
|
||||
|
||||
* [35]libpcre is required for using Perl-compatible regular expressions
|
||||
with --accept-regex and --reject-regex. You need the header files and
|
||||
the library installed to compile and link Wget with PCRE support.
|
||||
|
||||
* [36]pkg-config helps the ./configure script to find installed libraries.
|
||||
Most libraries provide a pkg-config file (.pc extension) with
|
||||
information about dependencies, header file and library locations.
|
||||
Distributions deliver their specific .pc file to each library.
|
||||
If you want to compile+link against your own library version, make a
|
||||
copy of the appropriate .pc file and amend it to your needs (e.g. edit
|
||||
the line starting with prefix=). Before you execute the ./configure
|
||||
script, set (and export) PKG_CONFIG_PATH to the directory where you
|
||||
saved the .pc file. Example:
|
||||
$ PKG_CONFIG_PATH="." ./configure
|
||||
|
||||
|
||||
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
|
||||
calling ./bootstrap.sh you're ready to build GNU Wget in the normal
|
||||
that point, a shell script called bootstrap has been provided. After
|
||||
calling ./bootstrap you're ready to build GNU Wget in the normal
|
||||
fashion, with ./configure and make.
|
||||
|
||||
So, to sum up, after checking out the source code as described above,
|
||||
@@ -80,15 +102,23 @@ Compiling From Repository Sources
|
||||
$ cd wget # assumes you've cloned a repository to "./wget"
|
||||
2. Generate all the automatically-generated files required prior to
|
||||
configuring the package:
|
||||
$ ./bootstrap.sh
|
||||
$ ./bootstrap
|
||||
3. Configure the package and compile it:
|
||||
$ ./configure [some_parameters]
|
||||
$ ./configure --enable-assert [some_parameters]
|
||||
$ make
|
||||
4. Hack, compile, test, hack, compile, test...
|
||||
$ src/wget --version
|
||||
GNU Wget 1.12-devel (9cb2563197bc)
|
||||
|
||||
Copyright © 2008,2010 Free Software Foundation, Inc.
|
||||
All developers are requested to enable the assertions on their development
|
||||
builds to ensure a stable codebase. Assertions are added to state certain
|
||||
assumptions about the code and its data which all developers should be mindful
|
||||
of. To enable assertions, run the configure command with the --enable-assert
|
||||
option, like this:
|
||||
|
||||
$ ./configure --enable-assert [other configure options]
|
||||
|
||||
Copyright (C) 2008,2010,2014,2015 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later
|
||||
<http://www.gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
@@ -96,21 +126,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.
|
||||
All content (C) 2007 Free Software Foundation. For terms of use,
|
||||
redistribution, and modification, please see the [45]WikiLicense page.
|
||||
|
||||
References
|
||||
|
||||
@@ -123,18 +153,19 @@ References
|
||||
26. http://apthorpe.cynistar.net/code/configuring_cpan.html
|
||||
27. http://www.gnu.org/software/texinfo/
|
||||
28. http://www.gnu.org/software/gettext/
|
||||
29. http://www.openssl.org/
|
||||
30. http://www.debian.org/
|
||||
31. http://www.gnu.org/software/gnutls/
|
||||
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
|
||||
29. http://www.gnu.org/software/gnutls/
|
||||
30. http://www.openssl.org/
|
||||
31. http://www.gnu.org/software/libidn/
|
||||
32. http://www.gnu.org/software/libiconv/
|
||||
33. http://git-scm.com/
|
||||
34. https://github.com/rockdaboot/libpsl
|
||||
35. http://www.pcre.org
|
||||
36. http://wget.addictivecode.org/CompilingRepoSources?action=edit&editor=text
|
||||
37. http://wget.addictivecode.org/CompilingRepoSources
|
||||
38. http://wget.addictivecode.org/CompilingRepoSources?action=info
|
||||
39. http://wget.addictivecode.org/CompilingRepoSources?action=AttachFile
|
||||
40. http://moinmo.in/
|
||||
41. http://moinmo.in/Python
|
||||
42. http://moinmo.in/GPL
|
||||
43. http://validator.w3.org/check?uri=referer
|
||||
44. http://wget.addictivecode.org/WikiLicense
|
||||
|
||||
237
bootstrap
237
bootstrap
@@ -1,10 +1,10 @@
|
||||
#! /bin/sh
|
||||
# Print a version string.
|
||||
scriptversion=2012-07-06.11; # UTC
|
||||
scriptversion=2013-12-05.23; # UTC
|
||||
|
||||
# Bootstrap this package from checked-out sources.
|
||||
|
||||
# Copyright (C) 2003-2012 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2003-2014 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
|
||||
@@ -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.
|
||||
|
||||
@@ -123,20 +140,21 @@ po_download_command_format2=\
|
||||
"wget --mirror -nd -q -np -A.po -P '%s' \
|
||||
http://translationproject.org/latest/%s/"
|
||||
|
||||
# Prefer a non-empty tarname (4th argument of AC_INIT if given), else
|
||||
# fall back to the package name (1st argument with munging)
|
||||
extract_package_name='
|
||||
/^AC_INIT(/{
|
||||
/.*,.*,.*, */{
|
||||
s///
|
||||
s/[][]//g
|
||||
s/)$//
|
||||
/^AC_INIT(\[*/{
|
||||
s///
|
||||
/^[^,]*,[^,]*,[^,]*,[ []*\([^][ ,)]\)/{
|
||||
s//\1/
|
||||
s/[],)].*//
|
||||
p
|
||||
q
|
||||
}
|
||||
s/AC_INIT(\[*//
|
||||
s/]*,.*//
|
||||
s/[],)].*//
|
||||
s/^GNU //
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
s/[^A-Za-z0-9_]/-/g
|
||||
s/[^abcdefghijklmnopqrstuvwxyz0123456789_]/-/g
|
||||
p
|
||||
}
|
||||
'
|
||||
@@ -191,12 +209,28 @@ bootstrap_sync=false
|
||||
# Use git to update gnulib sources
|
||||
use_git=true
|
||||
|
||||
check_exists() {
|
||||
if test "$1" = "--verbose"; then
|
||||
($2 --version </dev/null) >/dev/null 2>&1
|
||||
if test $? -ge 126; then
|
||||
# If not found, run with diagnostics as one may be
|
||||
# presented with env variables to set to find the right version
|
||||
($2 --version </dev/null)
|
||||
fi
|
||||
else
|
||||
($1 --version </dev/null) >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
test $? -lt 126
|
||||
}
|
||||
|
||||
# find_tool ENVVAR NAMES...
|
||||
# -------------------------
|
||||
# Search for a required program. Use the value of ENVVAR, if set,
|
||||
# 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.
|
||||
# otherwise find the first of the NAMES that can be run.
|
||||
# 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
|
||||
@@ -204,27 +238,21 @@ find_tool ()
|
||||
find_tool_names=$@
|
||||
eval "find_tool_res=\$$find_tool_envvar"
|
||||
if test x"$find_tool_res" = x; then
|
||||
for i
|
||||
do
|
||||
if ($i --version </dev/null) >/dev/null 2>&1; then
|
||||
find_tool_res=$i
|
||||
break
|
||||
for i; do
|
||||
if check_exists $i; then
|
||||
find_tool_res=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
find_tool_error_prefix="\$$find_tool_envvar: "
|
||||
fi
|
||||
test x"$find_tool_res" != x \
|
||||
|| die "one of these is required: $find_tool_names"
|
||||
($find_tool_res --version </dev/null) >/dev/null 2>&1 \
|
||||
|| die "${find_tool_error_prefix}cannot run $find_tool_res --version"
|
||||
if test x"$find_tool_res" = x; then
|
||||
warn_ "one of these is required: $find_tool_names;"
|
||||
die "alternatively set $find_tool_envvar to a compatible tool"
|
||||
fi
|
||||
eval "$find_tool_envvar=\$find_tool_res"
|
||||
eval "export $find_tool_envvar"
|
||||
}
|
||||
|
||||
# Find sha1sum, named gsha1sum on MacPorts, and shasum on Mac OS X 10.6.
|
||||
find_tool SHA1SUM sha1sum gsha1sum shasum
|
||||
|
||||
# Override the default configuration, if necessary.
|
||||
# Make sure that bootstrap.conf is sourced from the current directory
|
||||
# if we were invoked as "sh bootstrap".
|
||||
@@ -236,12 +264,12 @@ esac
|
||||
# Extra files from gnulib, which override files from other sources.
|
||||
test -z "${gnulib_extra_files}" && \
|
||||
gnulib_extra_files="
|
||||
$build_aux/install-sh
|
||||
$build_aux/mdate-sh
|
||||
$build_aux/texinfo.tex
|
||||
$build_aux/depcomp
|
||||
$build_aux/config.guess
|
||||
$build_aux/config.sub
|
||||
build-aux/install-sh
|
||||
build-aux/mdate-sh
|
||||
build-aux/texinfo.tex
|
||||
build-aux/depcomp
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
doc/INSTALL
|
||||
"
|
||||
|
||||
@@ -287,34 +315,34 @@ if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
|
||||
die "Bootstrapping from a non-checked-out distribution is risky."
|
||||
fi
|
||||
|
||||
# Ensure that lines starting with ! sort last, per gitignore conventions
|
||||
# for whitelisting exceptions after a more generic blacklist pattern.
|
||||
sort_patterns() {
|
||||
sort -u "$@" | sed '/^!/ {
|
||||
H
|
||||
d
|
||||
}
|
||||
$ {
|
||||
P
|
||||
x
|
||||
s/^\n//
|
||||
}' | sed '/^$/d'
|
||||
# Strip blank and comment lines to leave significant entries.
|
||||
gitignore_entries() {
|
||||
sed '/^#/d; /^$/d' "$@"
|
||||
}
|
||||
|
||||
# If $STR is not already on a line by itself in $FILE, insert it,
|
||||
# sorting the new contents of the file and replacing $FILE with the result.
|
||||
insert_sorted_if_absent() {
|
||||
# If $STR is not already on a line by itself in $FILE, insert it at the start.
|
||||
# Entries are inserted at the start of the ignore list to ensure existing
|
||||
# entries starting with ! are not overridden. Such entries support
|
||||
# whitelisting exceptions after a more generic blacklist pattern.
|
||||
insert_if_absent() {
|
||||
file=$1
|
||||
str=$2
|
||||
test -f $file || touch $file
|
||||
echo "$str" | sort_patterns - $file | cmp -s - $file > /dev/null \
|
||||
|| { echo "$str" | sort_patterns - $file > $file.bak \
|
||||
&& mv $file.bak $file; } \
|
||||
|| die "insert_sorted_if_absent $file $str: failed"
|
||||
test -r $file || die "Error: failed to read ignore file: $file"
|
||||
duplicate_entries=$(gitignore_entries $file | sort | uniq -d)
|
||||
if [ "$duplicate_entries" ] ; then
|
||||
die "Error: Duplicate entries in $file: " $duplicate_entries
|
||||
fi
|
||||
linesold=$(gitignore_entries $file | wc -l)
|
||||
linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l)
|
||||
if [ $linesold != $linesnew ] ; then
|
||||
{ echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \
|
||||
|| die "insert_if_absent $file $str: failed"
|
||||
fi
|
||||
}
|
||||
|
||||
# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with
|
||||
# insert_sorted_if_absent.
|
||||
# insert_if_absent.
|
||||
insert_vc_ignore() {
|
||||
vc_ignore_file="$1"
|
||||
pattern="$2"
|
||||
@@ -325,7 +353,7 @@ insert_vc_ignore() {
|
||||
# .gitignore entry.
|
||||
pattern=$(echo "$pattern" | sed s,^,/,);;
|
||||
esac
|
||||
insert_sorted_if_absent "$vc_ignore_file" "$pattern"
|
||||
insert_if_absent "$vc_ignore_file" "$pattern"
|
||||
}
|
||||
|
||||
# Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac.
|
||||
@@ -335,8 +363,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.
|
||||
@@ -391,7 +418,7 @@ sort_ver() { # sort -V is not generally available
|
||||
get_version() {
|
||||
app=$1
|
||||
|
||||
$app --version >/dev/null 2>&1 || return 1
|
||||
$app --version >/dev/null 2>&1 || { $app --version; return 1; }
|
||||
|
||||
$app --version 2>&1 |
|
||||
sed -n '# Move version to start of line.
|
||||
@@ -442,7 +469,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
|
||||
} ;;
|
||||
@@ -450,22 +477,22 @@ check_versions() {
|
||||
if [ "$req_ver" = "-" ]; then
|
||||
# Merely require app to exist; not all prereq apps are well-behaved
|
||||
# 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"
|
||||
if ! check_exists --verbose $app; then
|
||||
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
|
||||
@@ -483,6 +510,12 @@ print_versions() {
|
||||
# can't depend on column -t
|
||||
}
|
||||
|
||||
# Find sha1sum, named gsha1sum on MacPorts, shasum on Mac OS X 10.6.
|
||||
# Also find the compatible sha1 utility on the BSDs
|
||||
if test x"$SKIP_PO" = x; then
|
||||
find_tool SHA1SUM sha1sum gsha1sum shasum sha1
|
||||
fi
|
||||
|
||||
use_libtool=0
|
||||
# We'd like to use grep -E, to see if any of LT_INIT,
|
||||
# AC_PROG_LIBTOOL, AM_PROG_LIBTOOL is used in configure.ac,
|
||||
@@ -528,13 +561,21 @@ if ! printf "$buildreq" | check_versions; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Warn the user if autom4te appears to be broken; this causes known
|
||||
# issues with at least gettext 0.18.3.
|
||||
probe=$(echo 'm4_quote([hi])' | autom4te -l M4sugar -t 'm4_quote:$%' -)
|
||||
if test "x$probe" != xhi; then
|
||||
warn_ "WARNING: your autom4te wrapper eats stdin;"
|
||||
warn_ "if bootstrap fails, consider upgrading your autotools"
|
||||
fi
|
||||
|
||||
echo "$0: Bootstrapping from checked-out $package sources..."
|
||||
|
||||
# See if we can use gnulib's git-merge-changelog merge driver.
|
||||
if test -d .git && (git --version) >/dev/null 2>/dev/null ; then
|
||||
if $use_git && test -d .git && check_exists git; then
|
||||
if git config merge.merge-changelog.driver >/dev/null ; then
|
||||
:
|
||||
elif (git-merge-changelog --version) >/dev/null 2>/dev/null ; then
|
||||
elif check_exists git-merge-changelog; then
|
||||
echo "$0: initializing git-merge-changelog driver"
|
||||
git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver'
|
||||
git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B'
|
||||
@@ -554,17 +595,21 @@ git_modules_config () {
|
||||
test -f .gitmodules && git config --file .gitmodules "$@"
|
||||
}
|
||||
|
||||
gnulib_path=$(git_modules_config submodule.gnulib.path)
|
||||
test -z "$gnulib_path" && gnulib_path=gnulib
|
||||
if $use_git; then
|
||||
gnulib_path=$(git_modules_config submodule.gnulib.path)
|
||||
test -z "$gnulib_path" && gnulib_path=gnulib
|
||||
fi
|
||||
|
||||
# Get gnulib files.
|
||||
# Get gnulib files. Populate $GNULIB_SRCDIR, possibly updating a
|
||||
# submodule, for use in the rest of the script.
|
||||
|
||||
case ${GNULIB_SRCDIR--} in
|
||||
-)
|
||||
# Note that $use_git is necessarily true in this case.
|
||||
if git_modules_config submodule.gnulib.url >/dev/null; then
|
||||
echo "$0: getting gnulib files..."
|
||||
git submodule init || exit $?
|
||||
git submodule update || exit $?
|
||||
git submodule init -- "$gnulib_path" || exit $?
|
||||
git submodule update -- "$gnulib_path" || exit $?
|
||||
|
||||
elif [ ! -d "$gnulib_path" ]; then
|
||||
echo "$0: getting gnulib files..."
|
||||
@@ -581,8 +626,8 @@ case ${GNULIB_SRCDIR--} in
|
||||
GNULIB_SRCDIR=$gnulib_path
|
||||
;;
|
||||
*)
|
||||
# Use GNULIB_SRCDIR as a reference.
|
||||
if test -d "$GNULIB_SRCDIR"/.git && \
|
||||
# Use GNULIB_SRCDIR directly or as a reference.
|
||||
if $use_git && test -d "$GNULIB_SRCDIR"/.git && \
|
||||
git_modules_config submodule.gnulib.url >/dev/null; then
|
||||
echo "$0: getting gnulib files..."
|
||||
if git submodule -h|grep -- --reference > /dev/null; then
|
||||
@@ -593,13 +638,14 @@ case ${GNULIB_SRCDIR--} in
|
||||
# This fallback allows at least git 1.5.5.
|
||||
if test -f "$gnulib_path"/gnulib-tool; then
|
||||
# Since file already exists, assume submodule init already complete.
|
||||
git submodule update || exit $?
|
||||
git submodule update -- "$gnulib_path" || exit $?
|
||||
else
|
||||
# Older git can't clone into an empty directory.
|
||||
rmdir "$gnulib_path" 2>/dev/null
|
||||
git clone --reference "$GNULIB_SRCDIR" \
|
||||
"$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \
|
||||
&& git submodule init && git submodule update \
|
||||
&& git submodule init -- "$gnulib_path" \
|
||||
&& git submodule update -- "$gnulib_path" \
|
||||
|| exit $?
|
||||
fi
|
||||
fi
|
||||
@@ -608,12 +654,19 @@ case ${GNULIB_SRCDIR--} in
|
||||
;;
|
||||
esac
|
||||
|
||||
# $GNULIB_SRCDIR now points to the version of gnulib to use, and
|
||||
# we no longer need to use git or $gnulib_path below here.
|
||||
|
||||
if $bootstrap_sync; then
|
||||
cmp -s "$0" "$GNULIB_SRCDIR/build-aux/bootstrap" || {
|
||||
echo "$0: updating bootstrap and restarting..."
|
||||
case $(sh -c 'echo "$1"' -- a) in
|
||||
a) ignored=--;;
|
||||
*) ignored=ignored;;
|
||||
esac
|
||||
exec sh -c \
|
||||
'cp "$1" "$2" && shift && exec "${CONFIG_SHELL-/bin/sh}" "$@"' \
|
||||
-- "$GNULIB_SRCDIR/build-aux/bootstrap" \
|
||||
$ignored "$GNULIB_SRCDIR/build-aux/bootstrap" \
|
||||
"$0" "$@" --no-bootstrap-sync
|
||||
}
|
||||
fi
|
||||
@@ -661,11 +714,10 @@ update_po_files() {
|
||||
cksum_file="$ref_po_dir/$po.s1"
|
||||
if ! test -f "$cksum_file" ||
|
||||
! test -f "$po_dir/$po.po" ||
|
||||
! $SHA1SUM -c --status "$cksum_file" \
|
||||
< "$new_po" > /dev/null; then
|
||||
! $SHA1SUM -c "$cksum_file" < "$new_po" > /dev/null 2>&1; then
|
||||
echo "$me: updated $po_dir/$po.po..."
|
||||
cp "$new_po" "$po_dir/$po.po" \
|
||||
&& $SHA1SUM < "$new_po" > "$cksum_file"
|
||||
&& $SHA1SUM < "$new_po" > "$cksum_file" || return
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -761,7 +813,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
|
||||
}
|
||||
@@ -870,20 +922,21 @@ find "$m4_base" "$source_base" \
|
||||
-depth \( -name '*.m4' -o -name '*.[ch]' \) \
|
||||
-type l -xtype l -delete > /dev/null 2>&1
|
||||
|
||||
# Invoke autoreconf with --force --install to ensure upgrades of tools
|
||||
# such as ylwrap.
|
||||
AUTORECONFFLAGS="--verbose --install --force -I $m4_base $ACLOCAL_FLAGS"
|
||||
|
||||
# Some systems (RHEL 5) are using ancient autotools, for which the
|
||||
# --no-recursive option had not been invented. Detect that lack and
|
||||
# omit the option when it's not supported. FIXME in 2017: remove this
|
||||
# hack when RHEL 5 autotools are updated, or when they become irrelevant.
|
||||
no_recursive=
|
||||
case $($AUTORECONF --help) in
|
||||
*--no-recursive*) no_recursive=--no-recursive;;
|
||||
*--no-recursive*) AUTORECONFFLAGS="$AUTORECONFFLAGS --no-recursive";;
|
||||
esac
|
||||
|
||||
# Tell autoreconf not to invoke autopoint or libtoolize; they were run above.
|
||||
echo "running: AUTOPOINT=true LIBTOOLIZE=true " \
|
||||
"$AUTORECONF --verbose --install $no_recursive -I $m4_base $ACLOCAL_FLAGS"
|
||||
AUTOPOINT=true LIBTOOLIZE=true \
|
||||
$AUTORECONF --verbose --install $no_recursive -I $m4_base $ACLOCAL_FLAGS \
|
||||
echo "running: AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS"
|
||||
AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS \
|
||||
|| die "autoreconf failed"
|
||||
|
||||
# Get some extra files from gnulib, overriding existing files.
|
||||
|
||||
@@ -31,17 +31,24 @@ announce-gen
|
||||
base32
|
||||
bind
|
||||
c-ctype
|
||||
c-strcase
|
||||
c-strcasestr
|
||||
clock-time
|
||||
close
|
||||
connect
|
||||
dirname
|
||||
fcntl
|
||||
fnmatch
|
||||
futimens
|
||||
ftello
|
||||
getaddrinfo
|
||||
getline
|
||||
getopt-gnu
|
||||
getpass-gnu
|
||||
getpeername
|
||||
getsockname
|
||||
gettext
|
||||
gitlog-to-changelog
|
||||
git-version-gen
|
||||
gnupload
|
||||
ioctl
|
||||
@@ -49,12 +56,14 @@ iconv
|
||||
iconv-h
|
||||
listen
|
||||
maintainer-makefile
|
||||
mbiter
|
||||
mbtowc
|
||||
memrchr
|
||||
mkdir
|
||||
mkstemp
|
||||
mkostemp
|
||||
crypto/md5
|
||||
crypto/sha1
|
||||
pipe
|
||||
quote
|
||||
quotearg
|
||||
recv
|
||||
@@ -66,16 +75,21 @@ sigprocmask
|
||||
sigpipe
|
||||
snprintf
|
||||
socket
|
||||
spawn-pipe
|
||||
stdbool
|
||||
strcasestr
|
||||
strcase
|
||||
strerror_r-posix
|
||||
strptime
|
||||
strtok_r
|
||||
strtoll
|
||||
timegm
|
||||
tmpdir
|
||||
unlocked-io
|
||||
update-copyright
|
||||
vasprintf
|
||||
vsnprintf
|
||||
write
|
||||
xstrndup
|
||||
"
|
||||
|
||||
gnulib_extra_files="
|
||||
@@ -101,4 +115,5 @@ perl 5.5
|
||||
rsync -
|
||||
tar -
|
||||
xz -
|
||||
flex -
|
||||
"
|
||||
|
||||
@@ -100,7 +100,7 @@ EOC
|
||||
EOC
|
||||
}
|
||||
print $fh <<EOC;
|
||||
#else
|
||||
#else
|
||||
"-$name",
|
||||
#endif
|
||||
|
||||
@@ -137,3 +137,4 @@ __DATA__
|
||||
|
||||
#include "wget.h"
|
||||
#include <stdio.h>
|
||||
#include "version.h"
|
||||
|
||||
8
cfg.mk
8
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,17 +12,18 @@ 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 \
|
||||
\
|
||||
sc_program_name \
|
||||
|
||||
sc_makefile_at_at_check \
|
||||
sc_cast_of_argument_to_free \
|
||||
|
||||
#SHELL=bash -x
|
||||
show-vc-list-except:
|
||||
@$(VC_LIST_EXCEPT)
|
||||
|
||||
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|((msdos|vms)/.*)|ChangeLog-2014-12-10$$
|
||||
|
||||
403
configure.ac
403
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
|
||||
@@ -57,38 +57,101 @@ AC_CANONICAL_HOST
|
||||
AC_DEFINE_UNQUOTED([OS_TYPE], "$host_os",
|
||||
[Define to be the name of the operating system.])
|
||||
|
||||
|
||||
dnl
|
||||
dnl Process features.
|
||||
dnl Process External Libraries
|
||||
dnl
|
||||
|
||||
AC_ARG_WITH(ssl,
|
||||
[[ --without-ssl disable SSL autodetection
|
||||
--with-ssl={gnutls,openssl} specify the SSL backend. GNU TLS is the default.]])
|
||||
dnl Libpsl: Public Suffix List checking
|
||||
AC_ARG_WITH([libpsl],
|
||||
[AS_HELP_STRING([--without-libpsl], [disable support for libpsl cookie checking.])])
|
||||
|
||||
AC_ARG_WITH(zlib,
|
||||
[[ --without-zlib disable zlib ]])
|
||||
dnl SSL: Configure SSL backend to use
|
||||
AC_ARG_WITH([ssl],
|
||||
[AS_HELP_STRING([--with-ssl={gnutls,openssl}], [specify SSL backend. GNU TLS is the default.])])
|
||||
|
||||
AC_ARG_ENABLE(opie,
|
||||
[ --disable-opie disable support for opie or s/key FTP login],
|
||||
ENABLE_OPIE=$enableval, ENABLE_OPIE=yes)
|
||||
test x"${ENABLE_OPIE}" = xyes && AC_DEFINE([ENABLE_OPIE], 1,
|
||||
[Define if you want the Opie support for FTP compiled in.])
|
||||
|
||||
AC_ARG_ENABLE(digest,
|
||||
[ --disable-digest disable support for HTTP digest authorization],
|
||||
ENABLE_DIGEST=$enableval, ENABLE_DIGEST=yes)
|
||||
test x"${ENABLE_DIGEST}" = xyes && AC_DEFINE([ENABLE_DIGEST], 1,
|
||||
[Define if you want the HTTP Digest Authorization compiled in.])
|
||||
dnl Zlib: Configure use iof zlib for compression
|
||||
AC_ARG_WITH([zlib],
|
||||
[AS_HELP_STRING([--without-zlib], [disable zlib.])])
|
||||
|
||||
AC_ARG_ENABLE(ntlm,
|
||||
[ --disable-ntlm disable support for NTLM authorization],
|
||||
[ENABLE_NTLM=$enableval], [ENABLE_NTLM=auto])
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --disable-debug disable support for debugging output],
|
||||
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.])
|
||||
dnl
|
||||
dnl Process features
|
||||
dnl
|
||||
|
||||
dnl Opie: Support for opie s/key FTP logins
|
||||
AC_ARG_ENABLE([opie],
|
||||
[AS_HELP_STRING([--disable-opie], [disable support for opie or s/key FTP login])],
|
||||
[ENABLE_OPIE=$enableval],
|
||||
[ENABLE_OPIE=yes])
|
||||
|
||||
AS_IF([test "x$ENABLE_OPIE" = xyes],
|
||||
[AC_DEFINE([ENABLE_OPIE], [1], [Define if you want Opie support for FTP compiled in.])],
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
dnl Digest: Support for HTTP Digest Authentication
|
||||
AC_ARG_ENABLE([digest],
|
||||
[AS_HELP_STRING([--disable-digest], [disable support for HTTP digest authorization])],
|
||||
[ENABLE_DIGEST=$enableval],
|
||||
[ENABLE_DIGEST=yes])
|
||||
|
||||
AS_IF([test "x$ENABLE_DIGEST" = xyes],
|
||||
[AC_DEFINE([ENABLE_DIGEST], [1], [Define if you want the HTTP Digest Authorization compiled in.])],
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
dnl NTLM: Support for HTTP NTLM Authentication
|
||||
AC_ARG_ENABLE([ntlm],
|
||||
[AS_HELP_STRING([--disable-ntlm], [disable support for NTLM authorization])],
|
||||
[ENABLE_NTLM=$enableval],
|
||||
[ENABLE_NTLM=auto]
|
||||
)
|
||||
|
||||
|
||||
dnl Debug: Support for printing debugging output
|
||||
AC_ARG_ENABLE([debug],
|
||||
[AS_HELP_STRING([--disable-debug], [disable support for debugging output])],
|
||||
[ENABLE_DEBUG=$enableval],
|
||||
[ENABLE_DEBUG=yes])
|
||||
|
||||
AS_IF([test "x$ENABLE_DEBUG" = xyes],
|
||||
[AC_DEFINE([ENABLE_DEBUG], [1], [Define if you want the debug output support compiled in.])],
|
||||
[]
|
||||
)
|
||||
|
||||
dnl Valgrind-tests: Should test suite be run under valgrind?
|
||||
AC_ARG_ENABLE(valgrind-tests,
|
||||
[AS_HELP_STRING([--enable-valgrind-tests], [enable using Valgrind for tests])],
|
||||
[ENABLE_VALGRIND=$enableval],
|
||||
[ENABLE_VALGRIND=no])
|
||||
|
||||
AS_IF([test "x$ENABLE_VALGRIND" != xno], [
|
||||
AC_CHECK_PROG(HAVE_VALGRIND, valgrind, yes, no)
|
||||
AS_IF([test "x$HAVE_VALGRIND" = xyes], [
|
||||
VALGRIND_TESTS="1"
|
||||
AC_SUBST(VALGRIND_TESTS)
|
||||
VALGRIND_INFO="Test suite will be run under Valgrind"
|
||||
], [
|
||||
VALGRIND_INFO="Valgrind not found"
|
||||
])
|
||||
], [
|
||||
VALGRIND_INFO="Valgrind testing not enabled"
|
||||
])
|
||||
|
||||
AC_ARG_ENABLE(assert,
|
||||
[AS_HELP_STRING([--enable-assert], [enable assertions in code base])],
|
||||
[ENABLE_ASSERTION=$enableval],
|
||||
[ENABLE_ASSERTION=no]
|
||||
)
|
||||
|
||||
AS_IF([test "x$ENABLE_ASSERTION" != xyes], [
|
||||
CFLAGS="-DNDEBUG $CFLAGS"
|
||||
],
|
||||
[])
|
||||
|
||||
dnl
|
||||
dnl Find the compiler
|
||||
@@ -104,6 +167,12 @@ AC_AIX
|
||||
|
||||
gl_EARLY
|
||||
|
||||
dnl
|
||||
dnl Find python3
|
||||
dnl
|
||||
AM_PATH_PYTHON([3.0],,[:])
|
||||
AM_CONDITIONAL([HAVE_PYTHON3], [test "$PYTHON" != :])
|
||||
|
||||
dnl
|
||||
dnl Gettext
|
||||
dnl
|
||||
@@ -121,9 +190,11 @@ dnl if compiler is gcc, then
|
||||
dnl use -O2 and some warning flags
|
||||
dnl else
|
||||
dnl use os-specific flags or -O
|
||||
dnl
|
||||
dnl For these tests, the system considers clang to be gcc
|
||||
if test -n "$auto_cflags"; then
|
||||
if test -n "$GCC"; then
|
||||
CFLAGS="$CFLAGS -O2 -Wall"
|
||||
CFLAGS="$CFLAGS -O2 -Wall -Wextra"
|
||||
else
|
||||
case "$host_os" in
|
||||
*hpux*) CFLAGS="$CFLAGS +O3" ;;
|
||||
@@ -142,8 +213,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 +254,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,9 +266,9 @@ 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)
|
||||
AC_CHECK_FUNCS(sleep symlink utime strlcpy random)
|
||||
|
||||
if test x"$ENABLE_OPIE" = xyes; then
|
||||
AC_LIBOBJ([ftp-opie])
|
||||
@@ -237,14 +305,48 @@ dnl
|
||||
dnl Checks for libraries.
|
||||
dnl
|
||||
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AS_IF([test "x$with_libpsl" != xno], [
|
||||
PKG_CHECK_MODULES([LIBPSL], libpsl, [
|
||||
with_libpsl=yes
|
||||
# correct $LIBPSL_LIBS (in libpsl <= 0.6.0)
|
||||
AS_IF([test "x$LIBPSL_LIBS" = "x-llibpsl "], [LIBPSL_LIBS="-lpsl"])
|
||||
LIBS="$LIBPSL_LIBS $LIBS"
|
||||
CFLAGS="$LIBPSL_CFLAGS $CFLAGS"
|
||||
AC_DEFINE([HAVE_LIBPSL], [1], [PSL support enabled])
|
||||
], [
|
||||
AC_SEARCH_LIBS(psl_builtin, psl,
|
||||
[with_libpsl=yes; AC_DEFINE([HAVE_LIBPSL], [1], [PSL support enabled])],
|
||||
[with_libpsl=no; AC_MSG_WARN(*** libpsl was not found. Fallback to builtin cookie checking.)])
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test x"$with_zlib" != xno], [
|
||||
AC_CHECK_LIB(z, compress)
|
||||
with_zlib=yes
|
||||
PKG_CHECK_MODULES([ZLIB], zlib, [
|
||||
LIBS="$ZLIB_LIBS $LIBS"
|
||||
CFLAGS="$ZLIB_CFLAGS $CFLAGS"
|
||||
AC_DEFINE([HAVE_LIBZ], [1], [Define if using zlib.])
|
||||
], [
|
||||
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)
|
||||
|
||||
if [test x"$with_libssl_prefix" = x]; then
|
||||
PKG_CHECK_MODULES([OPENSSL], [openssl], [
|
||||
AC_MSG_NOTICE([compiling in support for SSL via OpenSSL])
|
||||
AC_LIBOBJ([openssl])
|
||||
LIBS="$OPENSSL_LIBS $LIBS"
|
||||
CFLAGS="$OPENSSL_CFLAGS -DHAVE_LIBSSL $CFLAGS"
|
||||
LIBSSL=" " # ntlm check below wants this
|
||||
AC_CHECK_FUNCS([RAND_egd])
|
||||
AC_DEFINE([HAVE_LIBSSL], [1], [Define if using openssl.])
|
||||
ssl_found=yes
|
||||
])
|
||||
fi
|
||||
if [test x"$ssl_found" != xyes]; then
|
||||
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
|
||||
@@ -257,7 +359,7 @@ AS_IF([test x"$with_ssl" = xopenssl], [
|
||||
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
|
||||
@@ -269,7 +371,7 @@ AS_IF([test x"$with_ssl" = xopenssl], [
|
||||
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
|
||||
@@ -278,55 +380,64 @@ AS_IF([test x"$with_ssl" = xopenssl], [
|
||||
;;
|
||||
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 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>
|
||||
], [SSL_library_init ()])
|
||||
if test x"$LIBSSL" != x
|
||||
then
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([compiling in support for SSL via OpenSSL])
|
||||
AC_LIBOBJ([openssl])
|
||||
LIBS="$LIBSSL $LIBS"
|
||||
elif test x"$with_ssl" != x
|
||||
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
|
||||
AS_IF([test x"$with_ssl" != xno], [
|
||||
dnl Now actually check for -lssl
|
||||
|
||||
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], [], [
|
||||
#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.])
|
||||
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
|
||||
ssl_found=yes
|
||||
AC_MSG_NOTICE([compiling in support for SSL via OpenSSL])
|
||||
AC_LIBOBJ([openssl])
|
||||
LIBS="$LIBSSL $LIBS"
|
||||
AC_CHECK_FUNCS([RAND_egd])
|
||||
elif test x"$with_ssl" != x
|
||||
then
|
||||
AC_MSG_ERROR([--with-ssl=openssl was given, but SSL is not available.])
|
||||
fi
|
||||
])
|
||||
fi
|
||||
], [
|
||||
# --with-ssl is not openssl: check if it's no
|
||||
AS_IF([test x"$with_ssl" != xno], [
|
||||
dnl default is -lgnutls
|
||||
with_ssl=gnutls
|
||||
|
||||
AC_CHECK_FUNCS(gnutls_priority_set_direct)
|
||||
]) # endif: --with-ssl == no?
|
||||
dnl Now actually check for -lgnutls
|
||||
if [test x"$with_libgnutls_prefix" = x]; then
|
||||
PKG_CHECK_MODULES([GNUTLS], [gnutls], [
|
||||
AC_MSG_NOTICE([compiling in support for SSL via GnuTLS])
|
||||
AC_LIBOBJ([gnutls])
|
||||
LIBS="$GNUTLS_LIBS $LIBS"
|
||||
CFLAGS="$GNUTLS_CFLAGS -DHAVE_LIBGNUTLS $CFLAGS"
|
||||
AC_DEFINE([HAVE_LIBGNUTLS], [1], [Define if using gnutls.])
|
||||
ssl_found=yes
|
||||
])
|
||||
fi
|
||||
if [test x"$ssl_found" != xyes]; then
|
||||
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([GnuTLS has not been found. Use --with-ssl=openssl if you explicitly want OpenSSL.])
|
||||
fi
|
||||
fi
|
||||
|
||||
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 +445,37 @@ 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
|
||||
|
||||
|
||||
dnl **********************************************************************
|
||||
dnl Checks for IPv6
|
||||
dnl **********************************************************************
|
||||
@@ -524,27 +653,65 @@ dnl
|
||||
dnl Check for UUID
|
||||
dnl
|
||||
|
||||
AC_CHECK_HEADER(uuid/uuid.h,
|
||||
AC_CHECK_LIB(uuid, uuid_generate,
|
||||
[LIBS="${LIBS} -luuid"
|
||||
AC_DEFINE([HAVE_LIBUUID], 1,
|
||||
[Define if libuuid is available.])
|
||||
])
|
||||
)
|
||||
AC_ARG_WITH(libuuid, AC_HELP_STRING([--without-libuuid],
|
||||
[Generate UUIDs for WARC files via libuuid]))
|
||||
|
||||
AS_IF([test "x$with_libuuid" = xyes], [
|
||||
# libuuid was explicitly requested
|
||||
PKG_CHECK_MODULES([UUID], uuid, [
|
||||
LIBS="$UUID_LIBS $LIBS"
|
||||
CFLAGS="$UUID_CFLAGS $CFLAGS"
|
||||
uuid_mode=1
|
||||
], [
|
||||
AC_SEARCH_LIBS(uuid_generate, uuid,
|
||||
[uuid_mode=1],
|
||||
[AC_MSG_ERROR(*** libuuid was explicitly requested but wasn't found.)])
|
||||
])
|
||||
], [test "x$with_libuuid" = xno], [
|
||||
# libuuid was explicitly *not* requested
|
||||
AC_CHECK_HEADER(uuid.h,
|
||||
AC_CHECK_FUNC(uuid_create, [uuid_mode=2]))
|
||||
], [
|
||||
# default:
|
||||
AC_CHECK_HEADER(uuid.h, [
|
||||
AC_CHECK_FUNC(uuid_create, [uuid_mode=2])
|
||||
], [
|
||||
AC_CHECK_HEADER(uuid/uuid.h,
|
||||
AC_SEARCH_LIBS(uuid_generate, uuid, [uuid_mode=1]))
|
||||
])
|
||||
])
|
||||
|
||||
AS_IF([test "x$uuid_mode" = x1], [
|
||||
AC_DEFINE([HAVE_LIBUUID], [1], [Define if using libuuid.])
|
||||
], [test "x$uuid_mode" = x2], [
|
||||
AC_DEFINE([HAVE_UUID_CREATE], 1, [Define if uuid_create is available.])
|
||||
])
|
||||
|
||||
dnl
|
||||
dnl Check for PCRE
|
||||
dnl
|
||||
|
||||
AC_CHECK_HEADER(pcre.h,
|
||||
AC_CHECK_LIB(pcre, pcre_compile,
|
||||
[LIBS="${LIBS} -lpcre"
|
||||
AC_DEFINE([HAVE_LIBPCRE], 1,
|
||||
[Define if libpcre is available.])
|
||||
])
|
||||
)
|
||||
AC_ARG_ENABLE(pcre, AC_HELP_STRING([--disable-pcre],
|
||||
[Disable PCRE style regular expressions]))
|
||||
|
||||
AS_IF([test "X$enable_pcre" != "Xno"],[
|
||||
PKG_CHECK_MODULES([PCRE], libpcre, [
|
||||
CFLAGS="$PCRE_CFLAGS $CFLAGS"
|
||||
AC_CHECK_HEADER(pcre.h, [
|
||||
LIBS="$PCRE_LIBS $LIBS"
|
||||
AC_DEFINE([HAVE_LIBPCRE], [1], [Define if libpcre is available.])
|
||||
])
|
||||
], [
|
||||
AC_CHECK_HEADER(pcre.h, [
|
||||
AC_CHECK_LIB(pcre, pcre_compile, [
|
||||
LIBS="${LIBS} -lpcre"
|
||||
AC_DEFINE([HAVE_LIBPCRE], 1, [Define if libpcre is available.])
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
|
||||
dnl Needed by src/Makefile.am
|
||||
AM_CONDITIONAL([IRI_IS_ENABLED], [test "X$iri" != "Xno"])
|
||||
|
||||
@@ -553,7 +720,27 @@ 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])
|
||||
po/Makefile.in tests/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: $with_libpsl
|
||||
Digest: $ENABLE_DIGEST
|
||||
NTLM: $ENABLE_NTLM
|
||||
OPIE: $ENABLE_OPIE
|
||||
Debugging: $ENABLE_DEBUG
|
||||
Assertions: $ENABLE_ASSERTION
|
||||
Valgrind: $VALGRIND_INFO
|
||||
])
|
||||
|
||||
52
contrib/check-hard
Executable file
52
contrib/check-hard
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Do some checking before 'git push'.
|
||||
|
||||
CORES=`grep -c ^processor /proc/cpuinfo 2>/dev/null || echo 0`
|
||||
if [ $CORES -lt 1 ]; then CORES=1; fi
|
||||
|
||||
make -f Makefile distclean 2>/dev/null
|
||||
|
||||
# automatically exit on error
|
||||
set -e
|
||||
|
||||
export CFLAGS="-std=c89 -pedantic -O2 -g -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wwrite-strings -Wshadow -Wformat -Wformat-security -Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition"
|
||||
|
||||
CACHEFILE=$PWD/config_check.cache
|
||||
|
||||
# measure time consumed and print it at the end of the script
|
||||
START=$(date +%s.%N)
|
||||
|
||||
echo "./bootstrap"
|
||||
./bootstrap >/dev/null
|
||||
echo
|
||||
|
||||
for CC in gcc clang; do
|
||||
export CC
|
||||
echo "*** checking CC=$CC"
|
||||
|
||||
# the compiler changed, so we have to remove the cache file here
|
||||
rm -f $CACHEFILE
|
||||
|
||||
for options in "" "--with-ssl=openssl"; do
|
||||
export DISTCHECK_CONFIGURE_FLAGS="-C --cache-file=$CACHEFILE $options"
|
||||
echo " ./configure $DISTCHECK_CONFIGURE_FLAGS"
|
||||
./configure $DISTCHECK_CONFIGURE_FLAGS >/dev/null
|
||||
|
||||
for xVALGRIND in 0 1; do
|
||||
for xLCALL in C tr_TR.utf8; do
|
||||
export TESTS_ENVIRONMENT="LC_ALL=$xLCALL VALGRIND_TESTS=$xVALGRIND"
|
||||
echo " TESTS_ENVIRONMENT=\"$TESTS_ENVIRONMENT\"" make check -j$CORES
|
||||
make check -j$CORES >/dev/null
|
||||
done
|
||||
done
|
||||
|
||||
unset TESTS_ENVIRONMENT
|
||||
export TESTS_ENVIRONMENT
|
||||
echo " make distcheck -j$CORES"
|
||||
make distcheck -j$CORES
|
||||
done
|
||||
done
|
||||
|
||||
END=$(date +%s.%N)
|
||||
echo "Duration: "$(echo "$END - $START" | bc)
|
||||
90
contrib/tsocked-wget
Executable file
90
contrib/tsocked-wget
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script that executes wget using a socks proxy if the environment variable
|
||||
# socks_proxy is set.
|
||||
#
|
||||
# The socks_proxy variable shall have one of the forms:
|
||||
# socks://username:password@host:port
|
||||
# socks4://username:password@host:port
|
||||
# socks5://username:password@host:port
|
||||
# with username, password and port fields being optional
|
||||
#
|
||||
# As socksification applies to the whole process, domains defined in the
|
||||
# no_proxy setting are *not* excluded.
|
||||
#
|
||||
|
||||
# Requisites: bash (version 3.2.3 or later), tsocks and wget
|
||||
|
||||
####################################
|
||||
# Copyright (C) 2014 Ángel González
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
set -eu
|
||||
|
||||
# Binary to be executed. Use an absolute path if installing this script as 'wget'
|
||||
WGET=wget
|
||||
|
||||
if [ -z "${socks_proxy:-}" ]; then
|
||||
exec "$WGET" "$@"
|
||||
fi
|
||||
|
||||
CONFIG=""
|
||||
|
||||
if [[ "${socks_proxy}" =~ ^socks[45]?:// ]]; then
|
||||
if [[ "${socks_proxy:5:1}" != ":" ]]; then
|
||||
CONFIG+="server_type = ${socks_proxy:5:1}"
|
||||
socks_proxy="${socks_proxy:9}"
|
||||
else
|
||||
socks_proxy="${socks_proxy:8}"
|
||||
fi
|
||||
elif [[ "${socks_proxy}" =~ ^[[:alnum:]]*:// ]]; then
|
||||
echo "Bad value specified for socks_proxy: $socks_proxy" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ "${socks_proxy}" =~ ^([^@:]*)(:([^@]*))?@ ]]; then
|
||||
unset TSOCKS_USERNAME
|
||||
CONFIG+="
|
||||
default_user = ${BASH_REMATCH[1]}"
|
||||
|
||||
if [ ! -z "${BASH_REMATCH[3]}" ]; then
|
||||
unset TSOCKS_PASSWORD
|
||||
CONFIG+="
|
||||
default_pass = ${BASH_REMATCH[3]}"
|
||||
fi
|
||||
socks_proxy="${socks_proxy:${#BASH_REMATCH[0]}}"
|
||||
fi
|
||||
|
||||
|
||||
# Get rid of trailing slashes
|
||||
if [[ "${socks_proxy}" =~ ^([^/]*)/ ]]; then
|
||||
socks_proxy="${socks_proxy:0:${#BASH_REMATCH[1]}}"
|
||||
fi
|
||||
|
||||
if [[ "${socks_proxy}" =~ :([0-9]+)$ ]]; then
|
||||
CONFIG+="
|
||||
server_port = ${BASH_REMATCH[1]}"
|
||||
socks_proxy=${socks_proxy:0:${#socks_proxy} - ${#BASH_REMATCH[0]}}
|
||||
fi
|
||||
|
||||
CONFIG+="
|
||||
server = ${socks_proxy}"
|
||||
|
||||
TSOCKS_CONF_FILE=<(echo "$CONFIG") exec tsocks "$WGET" --no-proxy "$@"
|
||||
1498
doc/ChangeLog
1498
doc/ChangeLog
File diff suppressed because it is too large
Load Diff
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).
|
||||
@@ -13,6 +16,9 @@
|
||||
## To use the settings in this file, you will have to uncomment them,
|
||||
## as well as change them, in most cases, as the values on the
|
||||
## commented-out lines are the default values (e.g. "off").
|
||||
##
|
||||
## Command are case-, underscore- and minus-insensitive.
|
||||
## For example ftp_proxy, ftp-proxy and ftpproxy are the same.
|
||||
|
||||
|
||||
##
|
||||
@@ -119,7 +125,13 @@
|
||||
#iri = off
|
||||
|
||||
# Force the default system encoding
|
||||
#locale = UTF-8
|
||||
#localencoding = UTF-8
|
||||
|
||||
# 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";
|
||||
|
||||
257
doc/wget.texi
257
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
|
||||
@@ -551,10 +550,10 @@ 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.
|
||||
@@ -631,6 +630,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 +701,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 +732,56 @@ 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.
|
||||
|
||||
This option will also force the progress bar to be printed to @file{stderr} when
|
||||
used alongside the @samp{--logfile} option.
|
||||
|
||||
@item -N
|
||||
@itemx --timestamping
|
||||
@@ -733,7 +790,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 +933,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 +1035,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
|
||||
@@ -1223,8 +1281,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 +1516,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 +1531,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 +1562,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 +1644,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
|
||||
protocol automatically, which is achieved by sending an SSLv2 greeting
|
||||
and announcing support for SSLv3 and TLSv1. This is the default.
|
||||
@samp{SSLv2}, @samp{SSLv3}, @samp{TLSv1}, @samp{TLSv1_1}, @samp{TLSv1_2}
|
||||
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 a TLSv1 greeting. 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.
|
||||
Specifying @samp{SSLv2}, @samp{SSLv3}, @samp{TLSv1}, @samp{TLSv1_1} or
|
||||
@samp{TLSv1_2} forces the use of the corresponding protocol. This is
|
||||
useful when talking to old and 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
|
||||
@@ -1625,19 +1728,23 @@ it allows Wget to fetch certificates on demand.
|
||||
Without this option Wget looks for CA certificates at the
|
||||
system-specified locations, chosen at OpenSSL installation time.
|
||||
|
||||
@cindex SSL CRL, certificate revocation list
|
||||
@item --crl-file=@var{file}
|
||||
Specifies a CRL file in @var{file}. This is needed for certificates
|
||||
that have been revocated by the CAs.
|
||||
|
||||
@cindex entropy, specifying source of
|
||||
@cindex randomness, specifying source of
|
||||
@item --random-file=@var{file}
|
||||
[OpenSSL and LibreSSL only]
|
||||
Use @var{file} as the source of random data for seeding the
|
||||
pseudo-random number generator on systems without @file{/dev/random}.
|
||||
pseudo-random number generator on systems without @file{/dev/urandom}.
|
||||
|
||||
On such systems the SSL library needs an external source of randomness
|
||||
to initialize. Randomness may be provided by EGD (see
|
||||
@samp{--egd-file} below) or read from an external source specified by
|
||||
the user. If this option is not specified, Wget looks for random data
|
||||
in @code{$RANDFILE} or, if that is unset, in @file{$HOME/.rnd}. If
|
||||
none of those are available, it is likely that SSL encryption will not
|
||||
be usable.
|
||||
in @code{$RANDFILE} or, if that is unset, in @file{$HOME/.rnd}.
|
||||
|
||||
If you're getting the ``Could not seed OpenSSL PRNG; disabling SSL.''
|
||||
error, you should provide random data using some of the methods
|
||||
@@ -1645,6 +1752,7 @@ described above.
|
||||
|
||||
@cindex EGD
|
||||
@item --egd-file=@var{file}
|
||||
[OpenSSL only]
|
||||
Use @var{file} as the EGD socket. EGD stands for @dfn{Entropy
|
||||
Gathering Daemon}, a user-space program that collects data from
|
||||
various unpredictable system sources and makes it available to other
|
||||
@@ -1659,7 +1767,7 @@ read random data from EGD socket specified using this option.
|
||||
|
||||
If this option is not specified (and the equivalent startup command is
|
||||
not used), EGD is never contacted. EGD is not needed on modern Unix
|
||||
systems that support @file{/dev/random}.
|
||||
systems that support @file{/dev/urandom}.
|
||||
@end table
|
||||
|
||||
@cindex WARC
|
||||
@@ -1715,8 +1823,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,19 +1885,24 @@ 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
|
||||
link is encountered, the linked-to file is not downloaded. Instead, a
|
||||
matching symbolic link is created on the local filesystem. The
|
||||
pointed-to file will not be downloaded unless this recursive retrieval
|
||||
would have encountered it separately and downloaded it anyway.
|
||||
By default, when retrieving @sc{ftp} directories recursively and a symbolic link
|
||||
is encountered, the symbolic link is traversed and the pointed-to files are
|
||||
retrieved. Currently, Wget does not traverse symbolic links to directories to
|
||||
download them recursively, though this feature may be added in the future.
|
||||
|
||||
When @samp{--retr-symlinks} is specified, however, symbolic links are
|
||||
traversed and the pointed-to files are retrieved. At this time, this
|
||||
option does not cause Wget to traverse symlinks to directories and
|
||||
recurse through them, but in the future it should be enhanced to do
|
||||
this.
|
||||
When @samp{--retr-symlinks=no} is specified, the linked-to file is not
|
||||
downloaded. Instead, a matching symbolic link is created on the local
|
||||
filesystem. The pointed-to file will not be retrieved unless this recursive
|
||||
retrieval would have encountered it separately and downloaded it anyway. This
|
||||
option poses a security risk where a malicious FTP Server may cause Wget to
|
||||
write to files outside of the intended directories through a specially crafted
|
||||
@sc{.listing} file.
|
||||
|
||||
Note that when retrieving a file (not a directory) because it was
|
||||
specified on the command-line, rather than because it was recursed to,
|
||||
@@ -2013,6 +2126,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 +2185,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
|
||||
@@ -2775,10 +2901,10 @@ variable = value
|
||||
The @dfn{variable} will also be called @dfn{command}. Valid
|
||||
@dfn{values} are different for different commands.
|
||||
|
||||
The commands are case-insensitive and underscore-insensitive. Thus
|
||||
@samp{DIr__PrefiX} is the same as @samp{dirprefix}. Empty lines, lines
|
||||
beginning with @samp{#} and lines containing white-space only are
|
||||
discarded.
|
||||
The commands are case-, underscore- and minus-insensitive. Thus
|
||||
@samp{DIr__PrefiX}, @samp{DIr-PrefiX} and @samp{dirprefix} are the same.
|
||||
Empty lines, lines beginning with @samp{#} and lines containing white-space
|
||||
only are discarded.
|
||||
|
||||
Commands that expect a comma-separated list will clear the list on an
|
||||
empty command. So, if you wish to reset the rejection list specified in
|
||||
@@ -2830,9 +2956,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,
|
||||
@@ -3006,6 +3134,9 @@ environment.
|
||||
Set @sc{http} user to @var{string}, equivalent to
|
||||
@samp{--http-user=@var{string}}.
|
||||
|
||||
@item https_only = on/off
|
||||
When in recursive mode, only HTTPS links are followed (defaults to off).
|
||||
|
||||
@item https_proxy = @var{string}
|
||||
Use @var{string} as @sc{https} proxy, instead of the one specified in
|
||||
environment.
|
||||
@@ -3094,7 +3225,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 +3736,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 +4448,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 ecc5d3e148
@@ -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,55 +0,0 @@
|
||||
2009-09-06 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* Makefile.WC: Added compilation of new file msdos.c.
|
||||
Simplified; no need to have explicit rules for files in ./lib and
|
||||
./md5. Just use the suffix search path mechanism in wmake.
|
||||
|
||||
2009-09-06 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* Makefile.DJ: Added compilation of new file msdos.c.
|
||||
|
||||
2009-09-05 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* config.h: Added 'HAVE_ALLOCA_H' for Watcom 1.5+. Added
|
||||
'USE_WATT32' since all DOS-targets use the Watt-32 tcp/ip stack.
|
||||
Added meaningless dummy LOCALEDIR.
|
||||
|
||||
* Makefile.WC: A much needed update. Added rules for many files
|
||||
in ./lib, css.c and version.c.
|
||||
|
||||
* Makefile.DJ: A much needed update. Added rules for css.c and
|
||||
version.c.
|
||||
|
||||
2008-01-25 Micah Cowan <micah@cowan.name>
|
||||
|
||||
* config.h: Updated copyright year.
|
||||
|
||||
2007-11-28 Micah Cowan <micah@cowan.name>
|
||||
|
||||
* config.h: Updated license exception for OpenSSL, per the SFLC.
|
||||
|
||||
2007-10-15 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* config.h: Added some HAVE_* for djgpp 2.04 and Watcom 1.7+.
|
||||
|
||||
* Makefile.DJ: rewritten for including some files from ../lib.
|
||||
|
||||
* Makefile.WC: Ditto. Handling source-files out-of current
|
||||
directory makes compliation a bit more painfull. AFAICS, one
|
||||
must use explicit rules.
|
||||
|
||||
2007-10-02 Gisle Vanem <gvanem@broadpark.no>
|
||||
|
||||
* config.h: Removed unused defines, added needed 'HAVE_*' defines.
|
||||
|
||||
* Makefile.DJ: rewritten to be used from './src' directory.
|
||||
Added '-DOPENSSL_NO_KRB5' for OpenSSL build. Target is
|
||||
now wget.exe.
|
||||
|
||||
* Makefile.WC: Added for building with OpenWatcom targeting
|
||||
32-bit DOS (DOS32A extender).
|
||||
|
||||
2007-09-24 Gisle Vanem <giva@bgnett.no>
|
||||
|
||||
* Makefile.DJ, config.h: Added to support building on MS-DOS via
|
||||
DJGPP.
|
||||
@@ -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
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
timestamp
|
||||
13528
src/ChangeLog
13528
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
|
||||
|
||||
|
||||
@@ -42,18 +42,18 @@ LIBS = @LIBICONV@ @LIBINTL@ @LIBS@ $(LIB_CLOCK_GETTIME)
|
||||
EXTRA_DIST = css.l css.c css_.c build_info.c.in
|
||||
|
||||
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 = 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 version.h
|
||||
nodist_wget_SOURCES = version.c
|
||||
EXTRA_wget_SOURCES = iri.c
|
||||
LDADD = $(LIBOBJS) ../lib/libgnu.a
|
||||
@@ -74,6 +74,7 @@ version.c: $(wget_SOURCES) ../lib/libgnu.a
|
||||
echo '/* version.c */' > $@
|
||||
echo '/* Autogenerated by Makefile - DO NOT EDIT */' >> $@
|
||||
echo '' >> $@
|
||||
echo '#include "version.h"' >> $@
|
||||
echo 'const char *version_string = "@VERSION@";' >> $@
|
||||
echo 'const char *compilation_string = "'$(COMPILE)'";' \
|
||||
| $(ESCAPEQUOTE) >> $@
|
||||
@@ -82,7 +83,7 @@ version.c: $(wget_SOURCES) ../lib/libgnu.a
|
||||
| $(ESCAPEQUOTE) >> $@
|
||||
|
||||
css.c: $(srcdir)/css.l
|
||||
$(LEX) $(LFLAGS) -o $@ $^
|
||||
$(LEX) $(LFLAGS) -o$@ $^
|
||||
|
||||
css_.c: css.c
|
||||
echo '#include "wget.h"' > $@
|
||||
|
||||
@@ -2,11 +2,12 @@ digest defined ENABLE_DIGEST
|
||||
https defined HAVE_SSL
|
||||
ipv6 defined ENABLE_IPV6
|
||||
iri defined ENABLE_IRI
|
||||
large-file SIZEOF_OFF_T >= 8
|
||||
large-file SIZEOF_OFF_T >= 8 || defined WINDOWS
|
||||
|
||||
nls defined ENABLE_NLS
|
||||
ntlm defined ENABLE_NTLM
|
||||
opie defined ENABLE_OPIE
|
||||
psl defined HAVE_LIBPSL
|
||||
|
||||
ssl choice:
|
||||
openssl defined HAVE_LIBSSL || defined HAVE_LIBSSL32
|
||||
|
||||
1427
src/cmpt.c
1427
src/cmpt.c
File diff suppressed because it is too large
Load Diff
@@ -54,15 +54,17 @@ as that of the covered work. */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef ENABLE_IRI
|
||||
#include <idn-free.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "host.h"
|
||||
#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). */
|
||||
@@ -171,7 +173,7 @@ sockaddr_size (const struct sockaddr *sa)
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Resolve the bind address specified via --bind-address and store it
|
||||
to SA. The resolved value is stored in a static variable and
|
||||
reused after the first invocation of this function.
|
||||
@@ -216,7 +218,7 @@ resolve_bind_address (struct sockaddr *sa)
|
||||
should_bind = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct cwt_context {
|
||||
int fd;
|
||||
const struct sockaddr *addr;
|
||||
@@ -253,7 +255,7 @@ connect_with_timeout (int fd, const struct sockaddr *addr, socklen_t addrlen,
|
||||
errno = ETIMEDOUT;
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
|
||||
/* Connect via TCP to the specified address and port.
|
||||
|
||||
If PRINT is non-NULL, it is the host name to print that we're
|
||||
@@ -273,7 +275,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)
|
||||
{
|
||||
@@ -281,22 +283,23 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
|
||||
str = xmalloc (len);
|
||||
snprintf (str, len, "%s (%s)", name, print);
|
||||
str[len-1] = '\0';
|
||||
xfree (name);
|
||||
idn_free (name);
|
||||
}
|
||||
|
||||
logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "),
|
||||
str ? str : escnonprint_uri (print), txt_addr, port);
|
||||
|
||||
if (str)
|
||||
xfree (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. */
|
||||
@@ -368,7 +371,7 @@ connect_to_ip (const ip_address *ip, int port, const char *print)
|
||||
if (sock >= 0)
|
||||
fd_close (sock);
|
||||
if (print)
|
||||
logprintf (LOG_VERBOSE, _("failed: %s.\n"), strerror (errno));
|
||||
logprintf (LOG_NOTQUIET, _("failed: %s.\n"), strerror (errno));
|
||||
errno = save_errno;
|
||||
return -1;
|
||||
}
|
||||
@@ -430,7 +433,7 @@ connect_to_host (const char *host, int port)
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Create a socket, bind it to local interface BIND_ADDRESS on port
|
||||
*PORT, set up a listen backlog, and return the resulting socket, or
|
||||
-1 in case of error.
|
||||
@@ -557,6 +560,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)
|
||||
{
|
||||
@@ -746,7 +750,7 @@ wget uses blocking sockets so we must convert them back to blocking
|
||||
or EOF/error. */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Basic socket operations, mostly EINTR wrappers. */
|
||||
|
||||
static int
|
||||
@@ -794,7 +798,7 @@ sock_close (int fd)
|
||||
#undef read
|
||||
#undef write
|
||||
#undef close
|
||||
|
||||
|
||||
/* Reading and writing from the network. We build around the socket
|
||||
(file descriptor) API, but support "extended" operations for things
|
||||
that are not mere file descriptors under the hood, such as SSL
|
||||
@@ -845,7 +849,7 @@ void *
|
||||
fd_transport_context (int fd)
|
||||
{
|
||||
struct transport_info *info = hash_table_get (transport_map, (void *)(intptr_t) fd);
|
||||
return info->ctx;
|
||||
return info ? info->ctx : NULL;
|
||||
}
|
||||
|
||||
/* When fd_read/fd_write are called multiple times in a loop, they should
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -125,7 +125,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);
|
||||
|
||||
@@ -465,7 +465,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 +626,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)
|
||||
{
|
||||
@@ -660,7 +661,7 @@ local_quote_string (const char *file, bool no_html_quote)
|
||||
|
||||
return no_html_quote ? strdup (newname) : html_quote_string (newname);
|
||||
}
|
||||
|
||||
|
||||
/* Book-keeping code for dl_file_url_map, dl_url_file_map,
|
||||
downloaded_html_list, and downloaded_html_set. Other code calls
|
||||
these functions to let us know that a file has been downloaded. */
|
||||
@@ -835,7 +836,7 @@ 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. */
|
||||
|
||||
@@ -915,7 +916,7 @@ convert_cleanup (void)
|
||||
if (converted_files)
|
||||
string_set_free (converted_files);
|
||||
}
|
||||
|
||||
|
||||
/* Book-keeping code for downloaded files that enables extension
|
||||
hacks. */
|
||||
|
||||
@@ -1011,7 +1012,7 @@ downloaded_files_free (void)
|
||||
downloaded_files_hash = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The function returns the pointer to the malloc-ed quoted version of
|
||||
string s. It will recognize and quote numeric and special graphic
|
||||
entities, as per RFC1866:
|
||||
@@ -1087,4 +1088,3 @@ html_quote_string (const char *s)
|
||||
/*
|
||||
* 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. */
|
||||
|
||||
135
src/cookies.c
135
src/cookies.c
@@ -51,11 +51,16 @@ 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"
|
||||
#include "http.h" /* for http_atotm */
|
||||
|
||||
#include "c-strcase.h"
|
||||
|
||||
|
||||
/* Declarations of `struct cookie' and the most basic functions. */
|
||||
|
||||
/* Cookie jar serves as cookie storage and a means of retrieving
|
||||
@@ -95,7 +100,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. */
|
||||
|
||||
@@ -148,13 +153,13 @@ cookie_expired_p (const struct cookie *c)
|
||||
static void
|
||||
delete_cookie (struct cookie *cookie)
|
||||
{
|
||||
xfree_null (cookie->domain);
|
||||
xfree_null (cookie->path);
|
||||
xfree_null (cookie->attr);
|
||||
xfree_null (cookie->value);
|
||||
xfree (cookie->domain);
|
||||
xfree (cookie->path);
|
||||
xfree (cookie->attr);
|
||||
xfree (cookie->value);
|
||||
xfree (cookie);
|
||||
}
|
||||
|
||||
|
||||
/* Functions for storing cookies.
|
||||
|
||||
All cookies can be reached beginning with jar->chains. The key in
|
||||
@@ -299,7 +304,12 @@ discard_matching_cookie (struct cookie_jar *jar, struct cookie *cookie)
|
||||
|
||||
res = hash_table_get_pair (jar->chains, victim->domain,
|
||||
&chain_key, NULL);
|
||||
assert (res != 0);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Unable to get cookie for %s\n"),
|
||||
victim->domain);
|
||||
}
|
||||
if (!victim->next)
|
||||
{
|
||||
/* VICTIM was the only cookie in the chain. Destroy the
|
||||
@@ -314,7 +324,7 @@ discard_matching_cookie (struct cookie_jar *jar, struct cookie *cookie)
|
||||
DEBUGP (("Discarded old cookie.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Functions for parsing the `Set-Cookie' header, and creating new
|
||||
cookies from the wire. */
|
||||
|
||||
@@ -346,7 +356,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,13 +370,13 @@ 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"))
|
||||
{
|
||||
if (!TOKEN_NON_EMPTY (value))
|
||||
goto error;
|
||||
xfree_null (cookie->domain);
|
||||
xfree (cookie->domain);
|
||||
/* Strictly speaking, we should set cookie->domain_exact if the
|
||||
domain doesn't begin with a dot. But many sites set the
|
||||
domain to "foo.com" and expect "subhost.foo.com" to get the
|
||||
@@ -379,7 +389,7 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
{
|
||||
if (!TOKEN_NON_EMPTY (value))
|
||||
goto error;
|
||||
xfree_null (cookie->path);
|
||||
xfree (cookie->path);
|
||||
cookie->path = strdupdelim (value.b, value.e);
|
||||
}
|
||||
else if (TOKEN_IS (name, "expires"))
|
||||
@@ -393,7 +403,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)
|
||||
{
|
||||
@@ -453,16 +463,16 @@ parse_set_cookie (const char *set_cookie, bool silent)
|
||||
|
||||
#undef TOKEN_IS
|
||||
#undef TOKEN_NON_EMPTY
|
||||
|
||||
|
||||
/* Sanity checks. These are important, otherwise it is possible for
|
||||
mailcious attackers to destroy important cookie information and/or
|
||||
violate your privacy. */
|
||||
|
||||
|
||||
#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 +508,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
|
||||
char *cookie_domain_lower = NULL;
|
||||
char *host_lower = NULL;
|
||||
const psl_ctx_t *psl;
|
||||
int is_acceptable;
|
||||
|
||||
DEBUGP (("cdm: 1"));
|
||||
if (!(psl = psl_builtin()))
|
||||
{
|
||||
DEBUGP (("\nlibpsl not built with a public suffix list. "
|
||||
"Falling back to simple heuristics.\n"));
|
||||
goto no_psl;
|
||||
}
|
||||
|
||||
/* 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_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;
|
||||
}
|
||||
|
||||
DEBUGP ((" 2"));
|
||||
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))
|
||||
@@ -647,7 +699,7 @@ check_path_match (const char *cookie_path, const char *path)
|
||||
s = PS_newstr; \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
/* Process the HTTP `Set-Cookie' header. This results in storing the
|
||||
cookie or discarding a matching one, or ignoring it completely, all
|
||||
depending on the contents. */
|
||||
@@ -673,9 +725,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 +736,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,7 +783,7 @@ cookie_handle_set_cookie (struct cookie_jar *jar,
|
||||
if (cookie)
|
||||
delete_cookie (cookie);
|
||||
}
|
||||
|
||||
|
||||
/* Support for sending out cookies in HTTP requests, based on
|
||||
previously stored cookies. Entry point is
|
||||
`build_cookies_request'. */
|
||||
@@ -1064,7 +1114,7 @@ cookie_header (struct cookie_jar *jar, const char *host,
|
||||
assert (pos == result_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Support for loading and saving cookies. The format used for
|
||||
loading and saving should be the format of the `cookies.txt' file
|
||||
used by Netscape and Mozilla, at least the Unix versions.
|
||||
@@ -1131,7 +1181,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 +1191,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 +1288,8 @@ cookie_jar_load (struct cookie_jar *jar, const char *file)
|
||||
abort_cookie:
|
||||
delete_cookie (cookie);
|
||||
}
|
||||
|
||||
xfree(line);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
@@ -1298,7 +1353,7 @@ cookie_jar_save (struct cookie_jar *jar, const char *file)
|
||||
|
||||
DEBUGP (("Done saving cookies.\n"));
|
||||
}
|
||||
|
||||
|
||||
/* Clean up cookie-related data. */
|
||||
|
||||
void
|
||||
@@ -1321,7 +1376,7 @@ cookie_jar_delete (struct cookie_jar *jar)
|
||||
hash_table_destroy (jar->chains);
|
||||
xfree (jar);
|
||||
}
|
||||
|
||||
|
||||
/* Test cases. Currently this is only tests parse_set_cookies. To
|
||||
use, recompile Wget with -DTEST_COOKIES and call test_cookies()
|
||||
from main. */
|
||||
@@ -1374,7 +1429,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);
|
||||
@@ -1390,8 +1445,8 @@ test_cookies (void)
|
||||
printf ("Invalid value %d for '%s' (expected '%s', got '%s')\n",
|
||||
j / 2 + 1, data, expected[j + 1], v);
|
||||
j += 2;
|
||||
free (n);
|
||||
free (v);
|
||||
xfree (n);
|
||||
xfree (v);
|
||||
}
|
||||
if (expected[j])
|
||||
printf ("Too few parameters for '%s'\n", data);
|
||||
|
||||
@@ -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>
|
||||
@@ -56,6 +52,7 @@ as that of the covered work. */
|
||||
#include "html-url.h"
|
||||
#include "css-tokens.h"
|
||||
#include "css-url.h"
|
||||
#include "xstrndup.h"
|
||||
|
||||
/* from lex.yy.c */
|
||||
extern char *yytext;
|
||||
@@ -64,41 +61,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 +73,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 +98,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 xstrndup (at + *pos, *length);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -161,12 +110,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 +143,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 */
|
||||
|
||||
27
src/exits.c
27
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,15 +50,15 @@ 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:
|
||||
case FTPRETRINT: case FTPRESTFAIL: case FTPNOPASV:
|
||||
case CONTNOTSUPPORTED: case RANGEERR: case RETRBADPATTERN:
|
||||
case PROXERR:
|
||||
case PROXERR: case GATEWAYTIMEOUT:
|
||||
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.
|
||||
@@ -43,10 +43,9 @@ as that of the covered work. */
|
||||
#include "host.h"
|
||||
#include "ftp.h"
|
||||
#include "retr.h"
|
||||
#include "c-strcase.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
|
||||
line is 0-terminated. All the response lines but the last one are
|
||||
@@ -84,8 +83,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;
|
||||
}
|
||||
@@ -194,7 +191,7 @@ ftp_login (int csock, const char *acc, const char *pass)
|
||||
for (i = 0; i < countof (skey_head); i++)
|
||||
{
|
||||
int l = strlen (skey_head[i]);
|
||||
if (0 == strncasecmp (skey_head[i], respline, l))
|
||||
if (0 == c_strncasecmp (skey_head[i], respline, l))
|
||||
{
|
||||
seed = respline + l;
|
||||
break;
|
||||
@@ -788,16 +785,8 @@ ftp_epsv (int csock, ip_address *ip, int *port)
|
||||
}
|
||||
|
||||
/* Finally, get the port number */
|
||||
tport = 0;
|
||||
for (i = 1; c_isdigit (*s); s++)
|
||||
{
|
||||
if (i > 5)
|
||||
{
|
||||
xfree (respline);
|
||||
return FTPINVPASV;
|
||||
}
|
||||
for (tport = 0, i = 0; i < 5 && c_isdigit (*s); i++, s++)
|
||||
tport = (*s - '0') + 10 * tport;
|
||||
}
|
||||
|
||||
/* Make sure that the response terminates correcty */
|
||||
if (*s++ != delim)
|
||||
@@ -960,23 +949,34 @@ 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. */
|
||||
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;
|
||||
/* 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. */
|
||||
static const char *list_commands[] = {
|
||||
"LIST -a",
|
||||
"LIST"
|
||||
};
|
||||
|
||||
*list_a_used = false;
|
||||
|
||||
if (avoid_list_a)
|
||||
{
|
||||
i = countof (list_commands)- 1;
|
||||
DEBUGP (("(skipping \"LIST -a\")"));
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
/* Send request. */
|
||||
@@ -1000,6 +1000,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 +1010,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 +1023,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 +1050,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,22 +1059,34 @@ 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"))
|
||||
else if (!c_strcasecmp (request, "VMS"))
|
||||
*server_type = ST_VMS;
|
||||
else if (!strcasecmp (request, "UNIX"))
|
||||
*server_type = ST_UNIX;
|
||||
else if (!strcasecmp (request, "WINDOWS_NT")
|
||||
|| !strcasecmp (request, "WINDOWS2000"))
|
||||
else if (!c_strcasecmp (request, "UNIX"))
|
||||
{
|
||||
*server_type = ST_UNIX;
|
||||
/* 2013-10-17 Andrea Urbani (matfanjol)
|
||||
I check more in depth the system type */
|
||||
if (!c_strncasecmp (ftp_last_respline, "215 UNIX Type: L8", 17))
|
||||
*unix_type = UST_TYPE_L8;
|
||||
else if (!c_strncasecmp (ftp_last_respline,
|
||||
"215 UNIX MultiNet Unix Emulation V5.3(93)", 41))
|
||||
*unix_type = UST_MULTINET;
|
||||
}
|
||||
else if (!c_strcasecmp (request, "WINDOWS_NT")
|
||||
|| !c_strcasecmp (request, "WINDOWS2000"))
|
||||
*server_type = ST_WINNT;
|
||||
else if (!strcasecmp (request, "MACOS"))
|
||||
else if (!c_strcasecmp (request, "MACOS"))
|
||||
*server_type = ST_MACOS;
|
||||
else if (!strcasecmp (request, "OS/400"))
|
||||
else if (!c_strcasecmp (request, "OS/400"))
|
||||
*server_type = ST_OS400;
|
||||
else
|
||||
*server_type = ST_OTHER;
|
||||
|
||||
xfree (ftp_last_respline);
|
||||
xfree (respline);
|
||||
/* All OK. */
|
||||
return FTPOK;
|
||||
@@ -1107,7 +1130,7 @@ ftp_pwd (int csock, char **pwd)
|
||||
goto err;
|
||||
|
||||
/* Has the `pwd' been already allocated? Free! */
|
||||
xfree_null (*pwd);
|
||||
xfree (*pwd);
|
||||
|
||||
*pwd = xstrdup (request);
|
||||
|
||||
|
||||
203
src/ftp-ls.c
203
src/ftp-ls.c
@@ -42,6 +42,7 @@ as that of the covered work. */
|
||||
#include "url.h"
|
||||
#include "convert.h" /* for html_quote_string prototype */
|
||||
#include "retr.h" /* for output_stream */
|
||||
#include "c-strcase.h"
|
||||
|
||||
/* Converts symbolic permissions to number-style ones, e.g. string
|
||||
rwxr-xr-x to 755. For now, it knows nothing of
|
||||
@@ -68,16 +69,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 +104,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 +118,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;
|
||||
}
|
||||
if (!c_strncasecmp (line, "total", 5))
|
||||
continue;
|
||||
/* Get the first token (permissions). */
|
||||
tok = strtok (line, " ");
|
||||
if (!tok)
|
||||
{
|
||||
xfree (line);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
cur.name = NULL;
|
||||
cur.linkto = NULL;
|
||||
@@ -203,7 +200,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 (!c_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. */
|
||||
@@ -366,9 +363,8 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
if (error || ignore)
|
||||
{
|
||||
DEBUGP (("Skipping.\n"));
|
||||
xfree_null (cur.name);
|
||||
xfree_null (cur.linkto);
|
||||
xfree (line);
|
||||
xfree (cur.name);
|
||||
xfree (cur.linkto);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -416,10 +412,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 +426,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 +442,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 +519,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 +560,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 +683,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 +701,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;
|
||||
|
||||
@@ -788,14 +776,14 @@ ftp_parse_vms_ls (const char *file)
|
||||
what will work in a CWD command.
|
||||
*/
|
||||
len = strlen (tok);
|
||||
if (!strncasecmp((tok + (len - 4)), ".DIR", 4))
|
||||
if (!c_strncasecmp((tok + (len - 4)), ".DIR", 4))
|
||||
{
|
||||
*(tok+ (len - 4)) = '\0'; /* Discard ".DIR". */
|
||||
cur.type = FT_DIRECTORY;
|
||||
cur.perms = VMS_DEFAULT_PROT_DIR;
|
||||
DEBUGP (("Directory (nv)\n"));
|
||||
}
|
||||
else if (!strncasecmp ((tok + (len - 6)), ".DIR;1", 6))
|
||||
else if (!c_strncasecmp ((tok + (len - 6)), ".DIR;1", 6))
|
||||
{
|
||||
*(tok+ (len - 6)) = '\0'; /* Discard ".DIR;1". */
|
||||
cur.type = FT_DIRECTORY;
|
||||
@@ -831,9 +819,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 +829,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 +848,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 +886,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 +896,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 +991,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;
|
||||
}
|
||||
@@ -1067,7 +1052,7 @@ Unsupported listing type, trying Unix listing parser.\n"));
|
||||
return ftp_parse_unix_ls (file, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Stuff for creating FTP index. */
|
||||
|
||||
/* The function creates an HTML index containing references to given
|
||||
@@ -1104,7 +1089,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f)
|
||||
else
|
||||
upwd = concat_strings (tmpu, "@", (char *) 0);
|
||||
xfree (tmpu);
|
||||
xfree_null (tmpp);
|
||||
xfree (tmpp);
|
||||
}
|
||||
else
|
||||
upwd = xstrdup ("");
|
||||
|
||||
513
src/ftp.c
513
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.
|
||||
@@ -50,6 +50,7 @@ as that of the covered work. */
|
||||
#include "convert.h" /* for downloaded_file */
|
||||
#include "recur.h" /* for INFINITE_RECURSION */
|
||||
#include "warc.h"
|
||||
#include "c-strcase.h"
|
||||
|
||||
#ifdef __VMS
|
||||
# include "vms.h"
|
||||
@@ -70,12 +71,12 @@ 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 */
|
||||
} ccon;
|
||||
|
||||
extern int numurls;
|
||||
|
||||
/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
|
||||
the string S, and return the number converted to wgint, if found, 0
|
||||
@@ -101,7 +102,7 @@ ftp_expected_bytes (const char *s)
|
||||
return 0;
|
||||
if (c_tolower (*s) != 'b')
|
||||
continue;
|
||||
if (strncasecmp (s, "byte", 4))
|
||||
if (c_strncasecmp (s, "byte", 4))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
@@ -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)
|
||||
@@ -407,7 +449,7 @@ Error in server response, closing control connection.\n"));
|
||||
return err;
|
||||
case FTPSRVERR :
|
||||
/* PWD unsupported -- assume "/". */
|
||||
xfree_null (con->id);
|
||||
xfree (con->id);
|
||||
con->id = xstrdup ("/");
|
||||
break;
|
||||
case FTPOK:
|
||||
@@ -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,76 +698,80 @@ 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++)
|
||||
{
|
||||
switch (cwd_count)
|
||||
for (cwd_count = cwd_start; cwd_count < cwd_end; cwd_count++)
|
||||
{
|
||||
case 0:
|
||||
/* Step one (optional): Go to the initial directory,
|
||||
exactly as reported by the server.
|
||||
*/
|
||||
targ = con->id;
|
||||
break;
|
||||
switch (cwd_count)
|
||||
{
|
||||
case 0:
|
||||
/* 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;
|
||||
break;
|
||||
case 1:
|
||||
/* Step two: Go to the target directory. (Absolute or
|
||||
relative will work now.)
|
||||
*/
|
||||
targ = target;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Step three (optional): "CWD []" to restore server
|
||||
VMS-ness.
|
||||
*/
|
||||
targ = "[]";
|
||||
break;
|
||||
case 2:
|
||||
/* Step three (optional): "CWD []" to restore server
|
||||
VMS-ness.
|
||||
*/
|
||||
targ = "[]";
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Can't happen. */
|
||||
assert (1);
|
||||
}
|
||||
default:
|
||||
logprintf (LOG_ALWAYS, _("Logically impossible section reached in getftp()"));
|
||||
logprintf (LOG_ALWAYS, _("cwd_count: %d\ncwd_start: %d\ncwd_end: %d\n"),
|
||||
cwd_count, cwd_start, cwd_end);
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ", cwd_count,
|
||||
quotearg_style (escape_quoting_style, target));
|
||||
err = ftp_cwd (csock, targ);
|
||||
/* FTPRERR, WRITEFAILED, FTPNSFOD */
|
||||
switch (err)
|
||||
{
|
||||
case FTPRERR:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_NOTQUIET, _("\
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, "==> CWD (%d) %s ... ", cwd_count,
|
||||
quotearg_style (escape_quoting_style, target));
|
||||
|
||||
err = ftp_cwd (csock, targ);
|
||||
|
||||
/* FTPRERR, WRITEFAILED, FTPNSFOD */
|
||||
switch (err)
|
||||
{
|
||||
case FTPRERR:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_NOTQUIET, _("\
|
||||
Error in server response, closing control connection.\n"));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case WRITEFAILED:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_NOTQUIET,
|
||||
_("Write failed, closing control connection.\n"));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case FTPNSFOD:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logprintf (LOG_NOTQUIET, _("No such directory %s.\n\n"),
|
||||
quote (u->dir));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case FTPOK:
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, _("done.\n"));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case WRITEFAILED:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_NOTQUIET,
|
||||
_("Write failed, closing control connection.\n"));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case FTPNSFOD:
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logprintf (LOG_NOTQUIET, _("No such directory %s.\n\n"),
|
||||
quote (u->dir));
|
||||
fd_close (csock);
|
||||
con->csock = -1;
|
||||
return err;
|
||||
case FTPOK:
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
} /* for */
|
||||
if (!opt.server_response)
|
||||
logputs (LOG_VERBOSE, _("done.\n"));
|
||||
|
||||
} /* for */
|
||||
|
||||
/* 2004-09-20 SMS. */
|
||||
/* End of deviant indenting. */
|
||||
|
||||
} /* else */
|
||||
}
|
||||
@@ -761,8 +807,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 +825,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 +991,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 +1083,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 +1093,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 +1132,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 +1164,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 +1237,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;
|
||||
@@ -1261,7 +1313,7 @@ Error in server response, closing control connection.\n"));
|
||||
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);
|
||||
|
||||
@@ -1313,6 +1365,7 @@ Error in server response, closing control connection.\n"));
|
||||
con->csock = -1;
|
||||
return FTPRETRINT;
|
||||
} /* err != FTPOK */
|
||||
*last_expected_bytes = ftp_expected_bytes (respline);
|
||||
/* 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
|
||||
@@ -1343,8 +1396,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 +1422,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;
|
||||
}
|
||||
|
||||
@@ -1405,6 +1553,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))
|
||||
@@ -1415,6 +1564,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
else
|
||||
{
|
||||
/* URL-derived file. Consider "-O file" name. */
|
||||
xfree (con->target);
|
||||
con->target = url_file_name (u, NULL);
|
||||
if (!opt.output_document)
|
||||
locf = con->target;
|
||||
@@ -1424,7 +1574,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 +1597,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 +1624,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))
|
||||
@@ -1524,7 +1681,8 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
|
||||
/* If we are working on a WARC record, getftp should also write
|
||||
to the warc_tmp file. */
|
||||
err = getftp (u, len, &qtyread, restval, con, count, warc_tmp);
|
||||
err = getftp (u, len, &qtyread, restval, con, count, &last_expected_bytes,
|
||||
warc_tmp);
|
||||
|
||||
if (con->csock == -1)
|
||||
con->st &= ~DONE_CWD;
|
||||
@@ -1549,7 +1707,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_fi
|
||||
if (err == FOPEN_EXCL_ERR)
|
||||
{
|
||||
/* Re-determine the file name. */
|
||||
xfree_null (con->target);
|
||||
xfree (con->target);
|
||||
con->target = url_file_name (u, NULL);
|
||||
locf = con->target;
|
||||
}
|
||||
@@ -1619,7 +1777,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)
|
||||
@@ -2058,6 +2216,29 @@ has_insecure_name_p (const char *s)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Test if the file node is invalid. This can occur due to malformed or
|
||||
* maliciously crafted listing files being returned by the server.
|
||||
*
|
||||
* Currently, this function only tests if there are multiple entries in the
|
||||
* listing file by the same name. However this function can be expanded as more
|
||||
* such illegal listing formats are discovered. */
|
||||
static bool
|
||||
is_invalid_entry (struct fileinfo *f)
|
||||
{
|
||||
struct fileinfo *cur = f;
|
||||
char *f_name = f->name;
|
||||
|
||||
/* If the node we're currently checking has a duplicate later, we eliminate
|
||||
* the current node and leave the next one intact. */
|
||||
while (cur->next)
|
||||
{
|
||||
cur = cur->next;
|
||||
if (strcmp(f_name, cur->name) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* A near-top-level function to retrieve the files in a directory.
|
||||
The function calls ftp_get_listing, to get a linked list of files.
|
||||
Then it weeds out the file names that do not match the pattern.
|
||||
@@ -2095,11 +2276,11 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action)
|
||||
f = f->next;
|
||||
}
|
||||
}
|
||||
/* Remove all files with possible harmful names */
|
||||
/* Remove all files with possible harmful names or invalid entries. */
|
||||
f = start;
|
||||
while (f)
|
||||
{
|
||||
if (has_insecure_name_p (f->name))
|
||||
if (has_insecure_name_p (f->name) || is_invalid_entry (f))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Rejecting %s.\n"),
|
||||
quote (f->name));
|
||||
@@ -2278,11 +2459,11 @@ 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);
|
||||
}
|
||||
@@ -2296,10 +2477,8 @@ ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy,
|
||||
/* If a connection was left, quench it. */
|
||||
if (con.csock != -1)
|
||||
fd_close (con.csock);
|
||||
xfree_null (con.id);
|
||||
con.id = NULL;
|
||||
xfree_null (con.target);
|
||||
con.target = NULL;
|
||||
xfree (con.id);
|
||||
xfree (con.target);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -2313,7 +2492,7 @@ delelement (struct fileinfo *f, struct fileinfo **start)
|
||||
struct fileinfo *next = f->next;
|
||||
|
||||
xfree (f->name);
|
||||
xfree_null (f->linkto);
|
||||
xfree (f->linkto);
|
||||
xfree (f);
|
||||
|
||||
if (next)
|
||||
|
||||
65
src/ftp.h
65
src/ftp.h
@@ -45,7 +45,13 @@ enum stype
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
extern char ftp_last_respline[];
|
||||
/* Extensions of the ST_UNIX */
|
||||
enum ustype
|
||||
{
|
||||
UST_TYPE_L8,
|
||||
UST_MULTINET,
|
||||
UST_OTHER
|
||||
};
|
||||
|
||||
uerr_t ftp_response (int, char **);
|
||||
uerr_t ftp_login (int, const char *, const char *);
|
||||
@@ -61,8 +67,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,34 +104,49 @@ 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);
|
||||
|
||||
272
src/gettext.h
272
src/gettext.h
@@ -1,272 +0,0 @@
|
||||
/* Convenience header for conditional use of GNU <libintl.h>.
|
||||
Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2009, 2010, 2011 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 2, 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
USA. */
|
||||
|
||||
#ifndef _LIBGETTEXT_H
|
||||
#define _LIBGETTEXT_H 1
|
||||
|
||||
/* NLS can be disabled through the configure --disable-nls option. */
|
||||
#if ENABLE_NLS
|
||||
|
||||
/* Get declarations of GNU message catalog functions. */
|
||||
# include <libintl.h>
|
||||
|
||||
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
|
||||
the gettext() and ngettext() macros. This is an alternative to calling
|
||||
textdomain(), and is useful for libraries. */
|
||||
# ifdef DEFAULT_TEXT_DOMAIN
|
||||
# undef gettext
|
||||
# define gettext(Msgid) \
|
||||
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
|
||||
# undef ngettext
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
|
||||
chokes if dcgettext is defined as a macro. So include it now, to make
|
||||
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
|
||||
as well because people using "gettext.h" will not include <libintl.h>,
|
||||
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
|
||||
is OK. */
|
||||
#if defined(__sun)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
|
||||
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
|
||||
it now, to make later inclusions of <libintl.h> a NOP. */
|
||||
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
|
||||
# include <cstdlib>
|
||||
# if (__GLIBC__ >= 2) || _GLIBCXX_HAVE_LIBINTL_H
|
||||
# include <libintl.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Disabled NLS.
|
||||
The casts to 'const char *' serve the purpose of producing warnings
|
||||
for invalid uses of the value returned from these functions.
|
||||
On pre-ANSI systems without 'const', the config.h file is supposed to
|
||||
contain "#define const". */
|
||||
# define gettext(Msgid) ((const char *) (Msgid))
|
||||
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
|
||||
# define dcgettext(Domainname, Msgid, Category) \
|
||||
((void) (Category), dgettext (Domainname, Msgid))
|
||||
# define ngettext(Msgid1, Msgid2, N) \
|
||||
((N) == 1 \
|
||||
? ((void) (Msgid2), (const char *) (Msgid1)) \
|
||||
: ((void) (Msgid1), (const char *) (Msgid2)))
|
||||
# define dngettext(Domainname, Msgid1, Msgid2, N) \
|
||||
((void) (Domainname), ngettext (Msgid1, Msgid2, N))
|
||||
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
|
||||
((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N))
|
||||
# define textdomain(Domainname) ((const char *) (Domainname))
|
||||
# define bindtextdomain(Domainname, Dirname) \
|
||||
((void) (Domainname), (const char *) (Dirname))
|
||||
# define bind_textdomain_codeset(Domainname, Codeset) \
|
||||
((void) (Domainname), (const char *) (Codeset))
|
||||
|
||||
#endif
|
||||
|
||||
/* A pseudo function call that serves as a marker for the automated
|
||||
extraction of messages, but does not call gettext(). The run-time
|
||||
translation is done at a different place in the code.
|
||||
The argument, String, should be a literal string. Concatenated strings
|
||||
and other string expressions won't work.
|
||||
The macro's expansion is not parenthesized, so that it is suitable as
|
||||
initializer for static 'char[]' or 'const char[]' variables. */
|
||||
#define gettext_noop(String) String
|
||||
|
||||
/* The separator between msgctxt and msgid in a .mo file. */
|
||||
#define GETTEXT_CONTEXT_GLUE "\004"
|
||||
|
||||
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
|
||||
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
|
||||
short and rarely need to change.
|
||||
The letter 'p' stands for 'particular' or 'special'. */
|
||||
#ifdef DEFAULT_TEXT_DOMAIN
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#else
|
||||
# define pgettext(Msgctxt, Msgid) \
|
||||
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#endif
|
||||
#define dpgettext(Domainname, Msgctxt, Msgid) \
|
||||
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
|
||||
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
|
||||
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
|
||||
#ifdef DEFAULT_TEXT_DOMAIN
|
||||
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#else
|
||||
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#endif
|
||||
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
|
||||
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
|
||||
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
pgettext_aux (const char *domain,
|
||||
const char *msg_ctxt_id, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
const char *translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
if (translation == msg_ctxt_id)
|
||||
return msgid;
|
||||
else
|
||||
return translation;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#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 *translation =
|
||||
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
|
||||
if (translation == msg_ctxt_id || translation == msgid_plural)
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
else
|
||||
return translation;
|
||||
}
|
||||
|
||||
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
|
||||
can be arbitrary expressions. But for string literals these macros are
|
||||
less efficient than those above. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \
|
||||
(((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \
|
||||
/* || __STDC_VERSION__ >= 199901L */ )
|
||||
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define pgettext_expr(Msgctxt, Msgid) \
|
||||
dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
|
||||
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
|
||||
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#endif
|
||||
static const char *
|
||||
dcpgettext_expr (const char *domain,
|
||||
const char *msgctxt, const char *msgid,
|
||||
int category)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
const char *translation;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof (buf)
|
||||
? buf
|
||||
: (char *) malloc (msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != NULL)
|
||||
#endif
|
||||
{
|
||||
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
translation = dcgettext (domain, msg_ctxt_id, category);
|
||||
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
if (msg_ctxt_id != buf)
|
||||
free (msg_ctxt_id);
|
||||
#endif
|
||||
if (translation != msg_ctxt_id)
|
||||
return translation;
|
||||
}
|
||||
return msgid;
|
||||
}
|
||||
|
||||
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
|
||||
dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
|
||||
|
||||
#ifdef __GNUC__
|
||||
__inline
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
inline
|
||||
#endif
|
||||
#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)
|
||||
{
|
||||
size_t msgctxt_len = strlen (msgctxt) + 1;
|
||||
size_t msgid_len = strlen (msgid) + 1;
|
||||
const char *translation;
|
||||
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
|
||||
char msg_ctxt_id[msgctxt_len + msgid_len];
|
||||
#else
|
||||
char buf[1024];
|
||||
char *msg_ctxt_id =
|
||||
(msgctxt_len + msgid_len <= sizeof (buf)
|
||||
? buf
|
||||
: (char *) malloc (msgctxt_len + msgid_len));
|
||||
if (msg_ctxt_id != NULL)
|
||||
#endif
|
||||
{
|
||||
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
|
||||
msg_ctxt_id[msgctxt_len - 1] = '\004';
|
||||
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
|
||||
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);
|
||||
#endif
|
||||
if (!(translation == msg_ctxt_id || translation == msgid_plural))
|
||||
return translation;
|
||||
}
|
||||
return (n == 1 ? msgid : msgid_plural);
|
||||
}
|
||||
|
||||
#endif /* _LIBGETTEXT_H */
|
||||
306
src/gnutls.c
306
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,106 @@ 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);
|
||||
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;
|
||||
|
||||
stat (ca_file, &st);
|
||||
ncerts = 0;
|
||||
|
||||
if (S_ISREG (st.st_mode))
|
||||
gnutls_certificate_set_x509_trust_file (credentials, ca_file,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
while ((dent = readdir (dir)) != NULL)
|
||||
{
|
||||
struct stat st;
|
||||
size_t ca_file_length = dirlen + strlen(dent->d_name) + 2;
|
||||
char *ca_file = alloca(ca_file_length);
|
||||
|
||||
free (ca_file);
|
||||
snprintf (ca_file, ca_file_length, "%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)
|
||||
DEBUGP (("WARNING: Failed to open cert %s: (%d).\n", ca_file, rc));
|
||||
else
|
||||
ncerts += rc;
|
||||
}
|
||||
|
||||
hash_table_destroy (inode_map);
|
||||
closedir (dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.ca_cert)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ncerts = 0;
|
||||
|
||||
if ((rc = gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
|
||||
GNUTLS_X509_FMT_PEM)) <= 0)
|
||||
logprintf (LOG_NOTQUIET, _ ("ERROR: Failed to open cert %s: (%d).\n"),
|
||||
opt.ca_cert, rc);
|
||||
else
|
||||
{
|
||||
ncerts += rc;
|
||||
logprintf (LOG_NOTQUIET, _ ("Loaded CA certificate '%s'\n"), opt.ca_cert);
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.crl_file)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if ((rc = gnutls_certificate_set_x509_crl_file (credentials, opt.crl_file, GNUTLS_X509_FMT_PEM)) <= 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("ERROR: Failed to load CRL file '%s': (%d)\n"), opt.crl_file, rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
closedir (dir);
|
||||
logprintf (LOG_NOTQUIET, _ ("Loaded CRL file '%s'\n"), opt.crl_file);
|
||||
}
|
||||
|
||||
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,23 +198,19 @@ 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)
|
||||
gnutls_certificate_set_x509_trust_file (credentials, opt.ca_cert,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
|
||||
ssl_initialized = true;
|
||||
|
||||
return true;
|
||||
@@ -176,11 +229,6 @@ struct wgnutls_transport_context
|
||||
int peeklen;
|
||||
};
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(i, j) ((i) <= (j) ? (i) : (j))
|
||||
#endif
|
||||
|
||||
|
||||
static int
|
||||
wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
@@ -278,7 +326,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 +363,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 +394,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 +422,21 @@ 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;
|
||||
const char *str;
|
||||
|
||||
gnutls_init (&session, GNUTLS_CLIENT);
|
||||
|
||||
/* We set the server name but only if it's not an IP address. */
|
||||
if (! is_valid_ip_address (hostname))
|
||||
{
|
||||
gnutls_server_name_set (session, GNUTLS_NAME_DNS, hostname,
|
||||
strlen (hostname));
|
||||
strlen (hostname));
|
||||
}
|
||||
|
||||
gnutls_set_default_priority (session);
|
||||
@@ -391,22 +444,46 @@ 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
|
||||
switch (opt.secure_protocol)
|
||||
{
|
||||
case secure_protocol_auto:
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:%COMPAT:-VERS-SSL3.0", NULL);
|
||||
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_tlsv1_1:
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0:-VERS-TLS1.0", NULL);
|
||||
break;
|
||||
|
||||
case secure_protocol_tlsv1_2:
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1", NULL);
|
||||
break;
|
||||
|
||||
case secure_protocol_pfs:
|
||||
err = gnutls_priority_set_direct (session, "PFS:-VERS-SSL3.0", NULL);
|
||||
if (err != GNUTLS_E_SUCCESS)
|
||||
/* fallback if PFS is not available */
|
||||
err = gnutls_priority_set_direct (session, "NORMAL:-RSA:-VERS-SSL3.0", NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
logprintf (LOG_NOTQUIET, _("GnuTLS: unimplemented 'secure-protocol' option value %d\n"), opt.secure_protocol);
|
||||
logprintf (LOG_NOTQUIET, _("Please report this issue to bug-wget@gnu.org\n"));
|
||||
abort ();
|
||||
}
|
||||
#else
|
||||
@@ -415,6 +492,7 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
{
|
||||
case secure_protocol_auto:
|
||||
break;
|
||||
|
||||
case secure_protocol_sslv2:
|
||||
case secure_protocol_sslv3:
|
||||
allowed_protocols[0] = GNUTLS_SSL3;
|
||||
@@ -428,7 +506,20 @@ ssl_connect_wget (int fd, const char *hostname)
|
||||
err = gnutls_protocol_set_priority (session, allowed_protocols);
|
||||
break;
|
||||
|
||||
case secure_protocol_tlsv1_1:
|
||||
allowed_protocols[0] = GNUTLS_TLS1_1;
|
||||
allowed_protocols[1] = GNUTLS_TLS1_2;
|
||||
err = gnutls_protocol_set_priority (session, allowed_protocols);
|
||||
break;
|
||||
|
||||
case secure_protocol_tlsv1_2:
|
||||
allowed_protocols[0] = GNUTLS_TLS1_2;
|
||||
err = gnutls_protocol_set_priority (session, allowed_protocols);
|
||||
break;
|
||||
|
||||
default:
|
||||
logprintf (LOG_NOTQUIET, _("GnuTLS: unimplemented 'secure-protocol' option value %d\n"), opt.secure_protocol);
|
||||
logprintf (LOG_NOTQUIET, _("Please report this issue to bug-wget@gnu.org\n"));
|
||||
abort ();
|
||||
}
|
||||
#endif
|
||||
@@ -440,10 +531,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)
|
||||
{
|
||||
gnutls_alert_description_t alert = gnutls_alert_get (session);
|
||||
str = gnutls_alert_get_name (alert);
|
||||
if (str == NULL)
|
||||
str = "(unknown)";
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n", alert, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 +617,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 +647,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 +675,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 +683,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 +702,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;
|
||||
|
||||
28
src/hash.c
28
src/hash.c
@@ -46,20 +46,17 @@ as that of the covered work. */
|
||||
# include "utils.h"
|
||||
#else
|
||||
/* Make do without them. */
|
||||
# define xnew(x) xmalloc (sizeof (x))
|
||||
# define xnew_array(type, x) xmalloc (sizeof (type) * (x))
|
||||
# define xmalloc malloc
|
||||
# define xfree free
|
||||
# define xnew(type) (xmalloc (sizeof (type)))
|
||||
# define xnew0(type) (xcalloc (1, sizeof (type)))
|
||||
# define xnew_array(type, len) (xmalloc ((len) * sizeof (type)))
|
||||
# define xfree(p) do { free ((void *) (p)); p = NULL; } while (0)
|
||||
|
||||
# ifndef countof
|
||||
# define countof(x) (sizeof (x) / sizeof ((x)[0]))
|
||||
# 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"
|
||||
@@ -589,7 +586,7 @@ hash_table_count (const struct hash_table *ht)
|
||||
{
|
||||
return ht->count;
|
||||
}
|
||||
|
||||
|
||||
/* Functions from this point onward are meant for convenience and
|
||||
don't strictly belong to this file. However, this is as good a
|
||||
place for them as any. */
|
||||
@@ -744,7 +741,7 @@ cmp_pointer (const void *ptr1, const void *ptr2)
|
||||
{
|
||||
return ptr1 == ptr2;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -767,6 +764,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 *);
|
||||
|
||||
28
src/host.c
28
src/host.c
@@ -57,6 +57,10 @@ as that of the covered work. */
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef ENABLE_IRI
|
||||
#include <idn-free.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "host.h"
|
||||
#include "url.h"
|
||||
@@ -151,6 +155,13 @@ address_list_set_faulty (struct address_list *al, int index)
|
||||
"faulty" attempt is always preceded with all-faulty addresses,
|
||||
and this is how Wget uses it. */
|
||||
assert (index == al->faulty);
|
||||
if (index != al->faulty)
|
||||
{
|
||||
logprintf (LOG_ALWAYS, "index: %d\nal->faulty: %d\n", index, al->faulty);
|
||||
logprintf (LOG_ALWAYS, _("Error in handling the address list.\n"));
|
||||
logprintf (LOG_ALWAYS, _("Please report this issue to bug-wget@gnu.org\n"));
|
||||
abort();
|
||||
}
|
||||
|
||||
++al->faulty;
|
||||
if (al->faulty >= al->count)
|
||||
@@ -309,7 +320,7 @@ address_list_release (struct address_list *al)
|
||||
address_list_delete (al);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Versions of gethostbyname and getaddrinfo that support timeout. */
|
||||
|
||||
#ifndef ENABLE_IPV6
|
||||
@@ -408,7 +419,7 @@ getaddrinfo_with_timeout (const char *node, const char *service,
|
||||
}
|
||||
|
||||
#endif /* ENABLE_IPV6 */
|
||||
|
||||
|
||||
/* Return a textual representation of ADDR, i.e. the dotted quad for
|
||||
IPv4 addresses, and the colon-separated list of hex words (with all
|
||||
zeros omitted, etc.) for IPv6 addresses. */
|
||||
@@ -570,7 +581,7 @@ is_valid_ipv6_address (const char *str, const char *end)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Simple host cache, used by lookup_host to speed up resolving. The
|
||||
cache doesn't handle TTL because Wget is a fairly short-lived
|
||||
application. Refreshing is attempted when connect fails, though --
|
||||
@@ -592,7 +603,7 @@ cache_query (const char *host)
|
||||
al = hash_table_get (host_name_addresses_map, host);
|
||||
if (al)
|
||||
{
|
||||
DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, al));
|
||||
DEBUGP (("Found %s in host_name_addresses_map (%p)\n", host, (void *) al));
|
||||
++al->refcount;
|
||||
return al;
|
||||
}
|
||||
@@ -637,7 +648,7 @@ cache_remove (const char *host)
|
||||
hash_table_remove (host_name_addresses_map, host);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Look up HOST in DNS and return a list of IP addresses.
|
||||
|
||||
This function caches its result so that, if the same host is passed
|
||||
@@ -734,14 +745,13 @@ lookup_host (const char *host, int flags)
|
||||
str = xmalloc (len);
|
||||
snprintf (str, len, "%s (%s)", name, host);
|
||||
str[len-1] = '\0';
|
||||
xfree (name);
|
||||
idn_free (name);
|
||||
}
|
||||
|
||||
logprintf (LOG_VERBOSE, _("Resolving %s... "),
|
||||
quotearg_style (escape_quoting_style, str ? str : host));
|
||||
|
||||
if (str)
|
||||
xfree (str);
|
||||
xfree (str);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
@@ -848,7 +858,7 @@ lookup_host (const char *host, int flags)
|
||||
|
||||
return al;
|
||||
}
|
||||
|
||||
|
||||
/* Determine whether a URL is acceptable to be followed, according to
|
||||
a list of domains to accept. */
|
||||
bool
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ struct pool {
|
||||
(sizevar) = ga_newsize; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Test whether n+1-sized entity name fits in P. We don't support
|
||||
IE-style non-terminated entities, e.g. "<foo" -> "<foo".
|
||||
However, "<foo" will work, as will "<!foo", "<", etc. In
|
||||
@@ -517,7 +517,7 @@ convert_and_copy (struct pool *pool, const char *beg, const char *end, int flags
|
||||
*p = c_tolower (*p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Originally we used to adhere to rfc 1866 here, and allowed only
|
||||
letters, digits, periods, and hyphens as names (of tags or
|
||||
attributes). However, this broke too many pages which used
|
||||
@@ -770,7 +770,7 @@ find_comment_end (const char *beg, const char *end)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the string containing of characters inside [b, e) is
|
||||
present in hash table HT. */
|
||||
|
||||
@@ -881,7 +881,7 @@ map_html_tags (const char *text, int size,
|
||||
if (*p == '!')
|
||||
{
|
||||
if (!(flags & MHT_STRICT_COMMENTS)
|
||||
&& p < end + 3 && p[1] == '-' && p[2] == '-')
|
||||
&& p + 3 < end && p[1] == '-' && p[2] == '-')
|
||||
{
|
||||
/* If strict comments are not enforced and if we know
|
||||
we're looking at a comment, simply look for the
|
||||
@@ -1167,7 +1167,7 @@ map_html_tags (const char *text, int size,
|
||||
#undef ADVANCE
|
||||
#undef SKIP_WS
|
||||
#undef SKIP_NON_WS
|
||||
|
||||
|
||||
#ifdef STANDALONE
|
||||
static void
|
||||
test_mapper (struct taginfo *taginfo, void *arg)
|
||||
@@ -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 */
|
||||
|
||||
@@ -45,6 +45,7 @@ as that of the covered work. */
|
||||
#include "recur.h"
|
||||
#include "html-url.h"
|
||||
#include "css-url.h"
|
||||
#include "c-strcase.h"
|
||||
|
||||
typedef void (*tag_handler_t) (int, struct taginfo *, struct map_context *);
|
||||
|
||||
@@ -79,7 +80,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 +114,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 +164,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,
|
||||
@@ -244,7 +256,7 @@ find_attr (struct taginfo *tag, const char *name, int *attrind)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < tag->nattrs; i++)
|
||||
if (!strcasecmp (tag->attrs[i].name, name))
|
||||
if (!c_strcasecmp (tag->attrs[i].name, name))
|
||||
{
|
||||
if (attrind)
|
||||
*attrind = i;
|
||||
@@ -273,6 +285,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 +306,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 +328,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 +339,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);
|
||||
@@ -361,7 +379,7 @@ append_url (const char *link_uri, int position, int size,
|
||||
|
||||
return newel;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_style_attr (struct taginfo *tag, struct map_context *ctx)
|
||||
{
|
||||
@@ -455,7 +473,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;
|
||||
@@ -470,8 +488,7 @@ tag_handle_base (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
base_urlpos->ignore_when_downloading = 1;
|
||||
base_urlpos->link_base_p = 1;
|
||||
|
||||
if (ctx->base)
|
||||
xfree (ctx->base);
|
||||
xfree (ctx->base);
|
||||
if (ctx->parent_base)
|
||||
ctx->base = uri_merge (ctx->parent_base, newbase);
|
||||
else
|
||||
@@ -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);
|
||||
@@ -519,12 +536,12 @@ tag_handle_link (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
char *rel = find_attr (tag, "rel", NULL);
|
||||
if (rel)
|
||||
{
|
||||
if (0 == strcasecmp (rel, "stylesheet"))
|
||||
if (0 == c_strcasecmp (rel, "stylesheet"))
|
||||
{
|
||||
up->link_inline_p = 1;
|
||||
up->link_expect_css = 1;
|
||||
}
|
||||
else if (0 == strcasecmp (rel, "shortcut icon"))
|
||||
else if (0 == c_strcasecmp (rel, "shortcut icon"))
|
||||
{
|
||||
up->link_inline_p = 1;
|
||||
}
|
||||
@@ -536,7 +553,7 @@ tag_handle_link (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
<link rel="alternate" type="application/rss+xml" href=".../?feed=rss2" />
|
||||
*/
|
||||
char *type = find_attr (tag, "type", NULL);
|
||||
if (!type || strcasecmp (type, "text/html") == 0)
|
||||
if (!type || c_strcasecmp (type, "text/html") == 0)
|
||||
up->link_expect_html = 1;
|
||||
}
|
||||
}
|
||||
@@ -548,12 +565,12 @@ 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);
|
||||
|
||||
if (http_equiv && 0 == strcasecmp (http_equiv, "refresh"))
|
||||
if (http_equiv && 0 == c_strcasecmp (http_equiv, "refresh"))
|
||||
{
|
||||
/* Some pages use a META tag to specify that the page be
|
||||
refreshed by a new page after a given number of seconds. The
|
||||
@@ -598,7 +615,7 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
entry->link_expect_html = 1;
|
||||
}
|
||||
}
|
||||
else if (http_equiv && 0 == strcasecmp (http_equiv, "content-type"))
|
||||
else if (http_equiv && 0 == c_strcasecmp (http_equiv, "content-type"))
|
||||
{
|
||||
/* Handle stuff like:
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=CHARSET"> */
|
||||
@@ -612,17 +629,17 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
if (!mcharset)
|
||||
return;
|
||||
|
||||
xfree_null (meta_charset);
|
||||
xfree (meta_charset);
|
||||
meta_charset = mcharset;
|
||||
}
|
||||
else if (name && 0 == strcasecmp (name, "robots"))
|
||||
else if (name && 0 == c_strcasecmp (name, "robots"))
|
||||
{
|
||||
/* Handle stuff like:
|
||||
<meta name="robots" content="index,nofollow"> */
|
||||
char *content = find_attr (tag, "content", NULL);
|
||||
if (!content)
|
||||
return;
|
||||
if (!strcasecmp (content, "none"))
|
||||
if (!c_strcasecmp (content, "none"))
|
||||
ctx->nofollow = true;
|
||||
else
|
||||
{
|
||||
@@ -634,7 +651,7 @@ tag_handle_meta (int tagid, struct taginfo *tag, struct map_context *ctx)
|
||||
/* Find the next occurrence of ',' or whitespace,
|
||||
* or the end of the string. */
|
||||
end = content + strcspn (content, ", \f\n\r\t\v");
|
||||
if (!strncasecmp (content, "nofollow", end - content))
|
||||
if (!c_strncasecmp (content, "nofollow", end - content))
|
||||
ctx->nofollow = true;
|
||||
/* Skip past the next comma, if any. */
|
||||
if (*end == ',')
|
||||
@@ -675,7 +692,7 @@ collect_tags_mapper (struct taginfo *tag, void *arg)
|
||||
|
||||
check_style_attr (tag, ctx);
|
||||
|
||||
if (tag->end_tag_p && (0 == strcasecmp (tag->name, "style"))
|
||||
if (tag->end_tag_p && (0 == c_strcasecmp (tag->name, "style"))
|
||||
&& tag->contents_begin && tag->contents_end
|
||||
&& tag->contents_begin <= tag->contents_end)
|
||||
{
|
||||
@@ -684,7 +701,7 @@ collect_tags_mapper (struct taginfo *tag, void *arg)
|
||||
tag->contents_end - tag->contents_begin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Analyze HTML tags FILE and construct a list of URLs referenced from
|
||||
it. It merges relative links in FILE with URL. It is aware of
|
||||
<base href=...> and does the right thing. */
|
||||
@@ -731,15 +748,16 @@ get_urls_html (const char *file, const char *url, bool *meta_disallow_follow,
|
||||
map_html_tags (fm->content, fm->length, collect_tags_mapper, &ctx, flags,
|
||||
NULL, interesting_attributes);
|
||||
|
||||
/* If meta charset isn't null, override content encoding */
|
||||
if (iri && meta_charset)
|
||||
/* Meta charset is only valid if there was no HTTP header Content-Type charset. */
|
||||
/* This is true for HTTP 1.0 and 1.1. */
|
||||
if (iri && !iri->content_encoding && meta_charset)
|
||||
set_content_encoding (iri, meta_charset);
|
||||
|
||||
DEBUGP (("no-follow in %s: %d\n", file, ctx.nofollow));
|
||||
if (meta_disallow_follow)
|
||||
*meta_disallow_follow = ctx.nofollow;
|
||||
|
||||
xfree_null (ctx.base);
|
||||
xfree (ctx.base);
|
||||
wget_read_file_free (fm);
|
||||
return ctx.head;
|
||||
}
|
||||
@@ -770,6 +788,7 @@ get_urls_file (const char *file)
|
||||
{
|
||||
int up_error_code;
|
||||
char *url_text;
|
||||
char *new_url;
|
||||
struct urlpos *entry;
|
||||
struct url *url;
|
||||
|
||||
@@ -804,6 +823,13 @@ get_urls_file (const char *file)
|
||||
url_text = merged;
|
||||
}
|
||||
|
||||
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 +856,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 */
|
||||
|
||||
292
src/http-ntlm.c
292
src/http-ntlm.c
@@ -42,68 +42,45 @@ 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
|
||||
long:
|
||||
@@ -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,82 +474,82 @@ ntlm_output (struct ntlmdata *ntlm, const char *user, const char *passwd,
|
||||
|
||||
/* Create the big type-3 message binary blob */
|
||||
|
||||
size = snprintf (ntlmbuf, sizeof(ntlmbuf),
|
||||
"NTLMSSP%c"
|
||||
"\x03%c%c%c" /* type-3, 32 bits */
|
||||
snprintf (ntlmbuf, sizeof (ntlmbuf),
|
||||
"NTLMSSP%c"
|
||||
"\x03%c%c%c" /* type-3, 32 bits */
|
||||
|
||||
"%c%c%c%c" /* LanManager length + allocated space */
|
||||
"%c%c" /* LanManager offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"%c%c%c%c" /* LanManager length + allocated space */
|
||||
"%c%c" /* LanManager offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
"%c%c" /* NT-response length */
|
||||
"%c%c" /* NT-response allocated space */
|
||||
"%c%c" /* NT-response offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"%c%c" /* NT-response length */
|
||||
"%c%c" /* NT-response allocated space */
|
||||
"%c%c" /* NT-response offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
"%c%c" /* domain length */
|
||||
"%c%c" /* domain allocated space */
|
||||
"%c%c" /* domain name offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"%c%c" /* domain length */
|
||||
"%c%c" /* domain allocated space */
|
||||
"%c%c" /* domain name offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
"%c%c" /* user length */
|
||||
"%c%c" /* user allocated space */
|
||||
"%c%c" /* user offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"%c%c" /* user length */
|
||||
"%c%c" /* user allocated space */
|
||||
"%c%c" /* user offset */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
"%c%c" /* host length */
|
||||
"%c%c" /* host allocated space */
|
||||
"%c%c" /* host offset */
|
||||
"%c%c%c%c%c%c" /* 6 zeroes */
|
||||
"%c%c" /* host length */
|
||||
"%c%c" /* host allocated space */
|
||||
"%c%c" /* host offset */
|
||||
"%c%c%c%c%c%c" /* 6 zeroes */
|
||||
|
||||
"\xff\xff" /* message length */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"\xff\xff" /* message length */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
"\x01\x82" /* flags */
|
||||
"%c%c" /* 2 zeroes */
|
||||
"\x01\x82" /* flags */
|
||||
"%c%c" /* 2 zeroes */
|
||||
|
||||
/* domain string */
|
||||
/* user string */
|
||||
/* host string */
|
||||
/* LanManager response */
|
||||
/* NT response */
|
||||
,
|
||||
0, /* zero termination */
|
||||
0,0,0, /* type-3 long, the 24 upper bits */
|
||||
/* domain string */
|
||||
/* user string */
|
||||
/* host string */
|
||||
/* LanManager response */
|
||||
/* NT response */
|
||||
,
|
||||
0, /* zero termination */
|
||||
0, 0, 0, /* type-3 long, the 24 upper bits */
|
||||
|
||||
SHORTPAIR(0x18), /* LanManager response length, twice */
|
||||
SHORTPAIR(0x18),
|
||||
SHORTPAIR(lmrespoff),
|
||||
0x0, 0x0,
|
||||
SHORTPAIR (0x18), /* LanManager response length, twice */
|
||||
SHORTPAIR (0x18),
|
||||
SHORTPAIR (lmrespoff),
|
||||
0x0, 0x0,
|
||||
|
||||
#ifdef USE_NTRESPONSES
|
||||
SHORTPAIR(0x18), /* NT-response length, twice */
|
||||
SHORTPAIR(0x18),
|
||||
SHORTPAIR (0x18), /* NT-response length, twice */
|
||||
SHORTPAIR (0x18),
|
||||
#else
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
#endif
|
||||
SHORTPAIR(ntrespoff),
|
||||
0x0, 0x0,
|
||||
SHORTPAIR (ntrespoff),
|
||||
0x0, 0x0,
|
||||
|
||||
SHORTPAIR(domlen),
|
||||
SHORTPAIR(domlen),
|
||||
SHORTPAIR(domoff),
|
||||
0x0, 0x0,
|
||||
SHORTPAIR (domlen),
|
||||
SHORTPAIR (domlen),
|
||||
SHORTPAIR (domoff),
|
||||
0x0, 0x0,
|
||||
|
||||
SHORTPAIR(userlen),
|
||||
SHORTPAIR(userlen),
|
||||
SHORTPAIR(useroff),
|
||||
0x0, 0x0,
|
||||
SHORTPAIR (userlen),
|
||||
SHORTPAIR (userlen),
|
||||
SHORTPAIR (useroff),
|
||||
0x0, 0x0,
|
||||
|
||||
SHORTPAIR(hostlen),
|
||||
SHORTPAIR(hostlen),
|
||||
SHORTPAIR(hostoff),
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
SHORTPAIR (hostlen),
|
||||
SHORTPAIR (hostlen),
|
||||
SHORTPAIR (hostoff),
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
0x0, 0x0,
|
||||
0x0, 0x0,
|
||||
|
||||
0x0, 0x0);
|
||||
0x0, 0x0);
|
||||
|
||||
/* size is now 64 */
|
||||
size=64;
|
||||
@@ -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);
|
||||
|
||||
732
src/http.c
732
src/http.c
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,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 */
|
||||
|
||||
348
src/init.c
348
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,9 @@ 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 */
|
||||
#include "html-url.h" /* for cleanup_html_url */
|
||||
#include "c-strcase.h"
|
||||
|
||||
#ifdef TESTING
|
||||
#include "test.h"
|
||||
@@ -87,7 +90,9 @@ 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_file_once);
|
||||
CMD_DECLARE (cmd_directory);
|
||||
CMD_DECLARE (cmd_time);
|
||||
CMD_DECLARE (cmd_vector);
|
||||
@@ -99,6 +104,7 @@ CMD_DECLARE (cmd_spec_htmlify);
|
||||
CMD_DECLARE (cmd_spec_mirror);
|
||||
CMD_DECLARE (cmd_spec_prefer_family);
|
||||
CMD_DECLARE (cmd_spec_progress);
|
||||
CMD_DECLARE (cmd_spec_progressdisp);
|
||||
CMD_DECLARE (cmd_spec_recursive);
|
||||
CMD_DECLARE (cmd_spec_regex_type);
|
||||
CMD_DECLARE (cmd_spec_restrict_file_names);
|
||||
@@ -136,6 +142,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,18 +154,19 @@ 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 },
|
||||
{ "continue", &opt.always_rest, cmd_boolean },
|
||||
{ "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 },
|
||||
#ifdef HAVE_SSL
|
||||
{ "crlfile", &opt.crl_file, cmd_file_once },
|
||||
#endif
|
||||
{ "defaultpage", &opt.default_page, cmd_string},
|
||||
{ "cutdirs", &opt.cut_dirs, cmd_number },
|
||||
{ "debug", &opt.debug, cmd_boolean },
|
||||
{ "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 +200,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 },
|
||||
@@ -210,9 +222,11 @@ static const struct {
|
||||
{ "logfile", &opt.lfilename, cmd_file },
|
||||
{ "login", &opt.ftp_user, cmd_string },/* deprecated*/
|
||||
{ "maxredirect", &opt.max_redirect, cmd_number },
|
||||
{ "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*/
|
||||
@@ -262,8 +276,10 @@ static const struct {
|
||||
#endif
|
||||
{ "serverresponse", &opt.server_response, cmd_boolean },
|
||||
{ "showalldnsentries", &opt.show_all_dns_entries, cmd_boolean },
|
||||
{ "showprogress", &opt.show_progress, cmd_spec_progressdisp },
|
||||
{ "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 },
|
||||
@@ -306,7 +322,7 @@ command_by_name (const char *cmdname)
|
||||
while (lo <= hi)
|
||||
{
|
||||
int mid = (lo + hi) >> 1;
|
||||
int cmp = strcasecmp (cmdname, commands[mid].name);
|
||||
int cmp = c_strcasecmp (cmdname, commands[mid].name);
|
||||
if (cmp < 0)
|
||||
hi = mid - 1;
|
||||
else if (cmp > 0)
|
||||
@@ -316,7 +332,7 @@ command_by_name (const char *cmdname)
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Reset the variables to default values. */
|
||||
void
|
||||
defaults (void)
|
||||
@@ -357,6 +373,22 @@ defaults (void)
|
||||
|
||||
opt.dns_cache = true;
|
||||
opt.ftp_pasv = true;
|
||||
/* 2014-09-07 Darshit Shah <darnir@gmail.com>
|
||||
* opt.retr_symlinks is set to true by default. Creating symbolic links on the
|
||||
* local filesystem pose a security threat by malicious FTP Servers that
|
||||
* server a specially crafted .listing file akin to this:
|
||||
*
|
||||
* lrwxrwxrwx 1 root root 33 Dec 25 2012 JoCxl6d8rFU -> /
|
||||
* drwxrwxr-x 15 1024 106 4096 Aug 28 02:02 JoCxl6d8rFU
|
||||
*
|
||||
* A .listing file in this fashion makes Wget susceptiple to a symlink attack
|
||||
* wherein the attacker is able to create arbitrary files, directories and
|
||||
* symbolic links on the target system and even set permissions.
|
||||
*
|
||||
* Hence, by default Wget attempts to retrieve the pointed-to files and does
|
||||
* not create the symbolic links locally.
|
||||
*/
|
||||
opt.retr_symlinks = true;
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
opt.check_cert = true;
|
||||
@@ -400,8 +432,13 @@ 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 = -1;
|
||||
opt.noscroll = false;
|
||||
}
|
||||
|
||||
|
||||
/* Return the user's home directory (strdup-ed), or NULL if none is
|
||||
found. */
|
||||
char *
|
||||
@@ -431,12 +468,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 +487,7 @@ home_dir (void)
|
||||
}
|
||||
|
||||
ret = home ? xstrdup (home) : NULL;
|
||||
if (buf)
|
||||
free (buf);
|
||||
xfree (buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -475,7 +506,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);
|
||||
}
|
||||
@@ -497,7 +528,7 @@ wgetrc_user_file_name (void)
|
||||
home = home_dir ();
|
||||
if (home)
|
||||
file = aprintf ("%s/.wgetrc", home);
|
||||
xfree_null (home);
|
||||
xfree (home);
|
||||
#endif /* def __VMS [else] */
|
||||
|
||||
if (!file)
|
||||
@@ -532,8 +563,7 @@ wgetrc_file_name (void)
|
||||
if (!file)
|
||||
{
|
||||
char *home = home_dir ();
|
||||
xfree_null (file);
|
||||
file = NULL;
|
||||
xfree (file);
|
||||
home = ws_mypath ();
|
||||
if (home)
|
||||
{
|
||||
@@ -541,7 +571,6 @@ wgetrc_file_name (void)
|
||||
if (!file_exists_p (file))
|
||||
{
|
||||
xfree (file);
|
||||
file = NULL;
|
||||
}
|
||||
xfree (home);
|
||||
}
|
||||
@@ -570,7 +599,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 +612,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;
|
||||
@@ -614,11 +644,11 @@ run_wgetrc (const char *file)
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
xfree_null (com);
|
||||
xfree_null (val);
|
||||
xfree (line);
|
||||
xfree (com);
|
||||
xfree (val);
|
||||
++ln;
|
||||
}
|
||||
xfree (line);
|
||||
fclose (fp);
|
||||
|
||||
return errcnt == 0;
|
||||
@@ -646,7 +676,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 +691,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 +713,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 +837,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 +854,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 +872,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,25 +880,25 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Generic helper functions, for use with `commands'. */
|
||||
|
||||
/* Forward declarations: */
|
||||
@@ -936,7 +966,7 @@ cmd_number (const char *com, const char *val, void *place)
|
||||
static bool
|
||||
cmd_number_inf (const char *com, const char *val, void *place)
|
||||
{
|
||||
if (!strcasecmp (val, "inf"))
|
||||
if (!c_strcasecmp (val, "inf"))
|
||||
{
|
||||
*(int *) place = 0;
|
||||
return true;
|
||||
@@ -947,25 +977,42 @@ 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;
|
||||
|
||||
xfree_null (*pstring);
|
||||
xfree (*pstring);
|
||||
*pstring = xstrdup (val);
|
||||
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 (*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;
|
||||
|
||||
xfree_null (*pstring);
|
||||
xfree (*pstring);
|
||||
|
||||
/* #### If VAL is empty, perhaps should set *PLACE to NULL. */
|
||||
|
||||
@@ -983,6 +1030,20 @@ cmd_file (const char *com, const char *val, void *place)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* like cmd_file, but insist on just a single option usage */
|
||||
static bool
|
||||
cmd_file_once (const char *com _GL_UNUSED, const char *val, void *place)
|
||||
{
|
||||
if (*(char **)place)
|
||||
{
|
||||
fprintf (stderr, _("%s: %s must only be used once\n"),
|
||||
exec_name, com);
|
||||
return false;
|
||||
}
|
||||
|
||||
return cmd_file(com, val, place);
|
||||
}
|
||||
|
||||
/* Like cmd_file, but strips trailing '/' characters. */
|
||||
static bool
|
||||
cmd_directory (const char *com, const char *val, void *place)
|
||||
@@ -1008,7 +1069,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 +1084,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;
|
||||
|
||||
@@ -1232,14 +1293,14 @@ cmd_cert_type (const char *com, const char *val, void *place)
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Specialized helper functions, used by `commands' to handle some
|
||||
options specially. */
|
||||
|
||||
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 +1314,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 +1335,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 +1356,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 +1368,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 +1390,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 +1409,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))
|
||||
{
|
||||
@@ -1356,10 +1417,10 @@ cmd_spec_progress (const char *com, const char *val, void *place_ignored)
|
||||
exec_name, com, quote (val));
|
||||
return false;
|
||||
}
|
||||
xfree_null (opt.progress_type);
|
||||
xfree (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 +1430,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 +1445,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 +1462,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,9 +1516,9 @@ 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;
|
||||
opt.report_bps = c_strcasecmp (val, "bits") == 0;
|
||||
if (!opt.report_bps)
|
||||
fprintf (stderr, _("%s: %s: Invalid value %s.\n"), exec_name, com, quote (val));
|
||||
return opt.report_bps;
|
||||
@@ -1472,6 +1533,9 @@ cmd_spec_secure_protocol (const char *com, const char *val, void *place)
|
||||
{ "sslv2", secure_protocol_sslv2 },
|
||||
{ "sslv3", secure_protocol_sslv3 },
|
||||
{ "tlsv1", secure_protocol_tlsv1 },
|
||||
{ "tlsv1_1", secure_protocol_tlsv1_1 },
|
||||
{ "tlsv1_2", secure_protocol_tlsv1_2 },
|
||||
{ "pfs", secure_protocol_pfs },
|
||||
};
|
||||
int ok = decode_string (val, choices, countof (choices), place);
|
||||
if (!ok)
|
||||
@@ -1483,7 +1547,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 +1559,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'))
|
||||
@@ -1504,27 +1568,44 @@ cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
|
||||
exec_name, com, quote (val));
|
||||
return false;
|
||||
}
|
||||
xfree_null (opt.useragent);
|
||||
xfree (opt.useragent);
|
||||
opt.useragent = xstrdup (val);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The --show-progress option is not a cmd_boolean since we need to keep track
|
||||
* of whether the user explicitly requested the option or not. -1 means
|
||||
* uninitialized. */
|
||||
static bool
|
||||
cmd_spec_progressdisp (const char *com, const char *val, void *place _GL_UNUSED)
|
||||
{
|
||||
bool flag;
|
||||
if (cmd_boolean (com, val, &flag))
|
||||
{
|
||||
opt.show_progress = flag;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* The "verbose" option cannot be cmd_boolean because the variable is
|
||||
not bool -- it's of type int (-1 means uninitialized because of
|
||||
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))
|
||||
{
|
||||
opt.verbose = flag;
|
||||
opt.show_progress = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Miscellaneous useful routines. */
|
||||
|
||||
/* A very simple atoi clone, more useful than atoi because it works on
|
||||
@@ -1659,7 +1740,7 @@ decode_string (const char *val, const struct decode_item *items, int itemcount,
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < itemcount; i++)
|
||||
if (0 == strcasecmp (val, items[i].name))
|
||||
if (0 == c_strcasecmp (val, items[i].name))
|
||||
{
|
||||
*place = items[i].code;
|
||||
return true;
|
||||
@@ -1667,10 +1748,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,94 +1780,88 @@ cleanup (void)
|
||||
res_cleanup ();
|
||||
http_cleanup ();
|
||||
cleanup_html_url ();
|
||||
spider_cleanup ();
|
||||
host_cleanup ();
|
||||
log_cleanup ();
|
||||
netrc_cleanup ();
|
||||
|
||||
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);
|
||||
xfree_null (opt.input_filename);
|
||||
xfree_null (opt.output_document);
|
||||
xfree (opt.choose_config);
|
||||
xfree (opt.lfilename);
|
||||
xfree (opt.dir_prefix);
|
||||
xfree (opt.input_filename);
|
||||
xfree (opt.output_document);
|
||||
free_vec (opt.accepts);
|
||||
free_vec (opt.rejects);
|
||||
free_vec (opt.excludes);
|
||||
free_vec (opt.includes);
|
||||
free_vec ((char **)opt.excludes);
|
||||
free_vec ((char **)opt.includes);
|
||||
free_vec (opt.domains);
|
||||
free_vec (opt.follow_tags);
|
||||
free_vec (opt.ignore_tags);
|
||||
xfree_null (opt.progress_type);
|
||||
xfree_null (opt.ftp_user);
|
||||
xfree_null (opt.ftp_passwd);
|
||||
xfree_null (opt.ftp_proxy);
|
||||
xfree_null (opt.https_proxy);
|
||||
xfree_null (opt.http_proxy);
|
||||
xfree (opt.progress_type);
|
||||
xfree (opt.ftp_user);
|
||||
xfree (opt.ftp_passwd);
|
||||
xfree (opt.ftp_proxy);
|
||||
xfree (opt.https_proxy);
|
||||
xfree (opt.http_proxy);
|
||||
free_vec (opt.no_proxy);
|
||||
xfree_null (opt.useragent);
|
||||
xfree_null (opt.referer);
|
||||
xfree_null (opt.http_user);
|
||||
xfree_null (opt.http_passwd);
|
||||
xfree (opt.useragent);
|
||||
xfree (opt.referer);
|
||||
xfree (opt.http_user);
|
||||
xfree (opt.http_passwd);
|
||||
free_vec (opt.user_headers);
|
||||
free_vec (opt.warc_user_headers);
|
||||
# ifdef HAVE_SSL
|
||||
xfree_null (opt.cert_file);
|
||||
xfree_null (opt.private_key);
|
||||
xfree_null (opt.ca_directory);
|
||||
xfree_null (opt.ca_cert);
|
||||
xfree_null (opt.random_file);
|
||||
xfree_null (opt.egd_file);
|
||||
xfree (opt.cert_file);
|
||||
xfree (opt.private_key);
|
||||
xfree (opt.ca_directory);
|
||||
xfree (opt.ca_cert);
|
||||
xfree (opt.crl_file);
|
||||
xfree (opt.random_file);
|
||||
xfree (opt.egd_file);
|
||||
# endif
|
||||
xfree_null (opt.bind_address);
|
||||
xfree_null (opt.cookies_input);
|
||||
xfree_null (opt.cookies_output);
|
||||
xfree_null (opt.user);
|
||||
xfree_null (opt.passwd);
|
||||
xfree_null (opt.base_href);
|
||||
xfree (opt.bind_address);
|
||||
xfree (opt.cookies_input);
|
||||
xfree (opt.cookies_output);
|
||||
xfree (opt.user);
|
||||
xfree (opt.passwd);
|
||||
xfree (opt.base_href);
|
||||
xfree (opt.method);
|
||||
xfree (opt.post_file_name);
|
||||
xfree (opt.post_data);
|
||||
xfree (opt.body_data);
|
||||
xfree (opt.body_file);
|
||||
|
||||
#endif /* DEBUG_MALLOC */
|
||||
}
|
||||
|
||||
|
||||
/* Unit testing routines. */
|
||||
|
||||
#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 (c_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;
|
||||
bool expected_restrict_files_ctrl;
|
||||
int expected_restrict_files_case;
|
||||
bool result;
|
||||
} test_array[] = {
|
||||
@@ -1800,7 +1871,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;
|
||||
|
||||
@@ -1815,13 +1886,12 @@ test_cmd_spec_restrict_file_names()
|
||||
*/
|
||||
mu_assert ("test_cmd_spec_restrict_file_names: wrong result",
|
||||
res == test_array[i].result
|
||||
&& opt.restrict_files_os == test_array[i].expected_restrict_files_os
|
||||
&& (int) opt.restrict_files_os == test_array[i].expected_restrict_files_os
|
||||
&& opt.restrict_files_ctrl == test_array[i].expected_restrict_files_ctrl
|
||||
&& opt.restrict_files_case == test_array[i].expected_restrict_files_case);
|
||||
&& (int) opt.restrict_files_case == test_array[i].expected_restrict_files_case);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
|
||||
139
src/iri.c
139
src/iri.c
@@ -35,18 +35,20 @@ as that of the covered work. */
|
||||
#include <iconv.h>
|
||||
#include <stringprep.h>
|
||||
#include <idna.h>
|
||||
#include <idn-free.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "url.h"
|
||||
#include "c-strcase.h"
|
||||
#include "c-strcasestr.h"
|
||||
#include "xstrndup.h"
|
||||
|
||||
/* RFC3987 section 3.1 mandates STD3 ASCII RULES */
|
||||
#define IDNA_FLAGS IDNA_USE_STD3_ASCII_RULES
|
||||
|
||||
/* Note: locale encoding is kept in options struct (opt.locale) */
|
||||
|
||||
static bool do_conversion (iconv_t cd, char *in, size_t inlen, char **out);
|
||||
|
||||
|
||||
/* Given a string containing "charset=XXX", return the encoding if found,
|
||||
or NULL otherwise */
|
||||
char *
|
||||
@@ -57,7 +59,7 @@ parse_charset (char *str)
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
str = strcasestr (str, "charset=");
|
||||
str = c_strcasestr (str, "charset=");
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
@@ -110,52 +112,35 @@ check_encoding_name (char *encoding)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Try converting string str from locale to UTF-8. Return a new string
|
||||
on success, or str on error or if conversion isn't needed. */
|
||||
const char *
|
||||
locale_to_utf8 (const char *str)
|
||||
{
|
||||
iconv_t l2u;
|
||||
char *new;
|
||||
|
||||
/* That shouldn't happen, just in case */
|
||||
if (!opt.locale)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("locale_to_utf8: locale is unset\n"));
|
||||
opt.locale = find_locale ();
|
||||
}
|
||||
|
||||
if (!opt.locale || !strcasecmp (opt.locale, "utf-8"))
|
||||
return str;
|
||||
|
||||
l2u = iconv_open ("UTF-8", opt.locale);
|
||||
if (l2u != (iconv_t)(-1))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Conversion from %s to %s isn't supported\n"),
|
||||
quote (opt.locale), quote ("UTF-8"));
|
||||
return str;
|
||||
}
|
||||
|
||||
if (do_conversion (l2u, (char *) str, strlen ((char *) str), &new))
|
||||
return (const char *) new;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Do the conversion according to the passed conversion descriptor cd. *out
|
||||
will contain the transcoded string on success. *out content is
|
||||
unspecified otherwise. */
|
||||
static bool
|
||||
do_conversion (iconv_t cd, char *in, size_t inlen, char **out)
|
||||
do_conversion (const char *tocode, const char *fromcode, char *in, size_t inlen, char **out)
|
||||
{
|
||||
iconv_t cd;
|
||||
/* sXXXav : hummm hard to guess... */
|
||||
size_t len, done, outlen = inlen * 2;
|
||||
size_t len, done, outlen;
|
||||
int invalid = 0, tooshort = 0;
|
||||
char *s;
|
||||
char *s, *in_org, *in_save;
|
||||
|
||||
s = xmalloc (outlen + 1);
|
||||
*out = s;
|
||||
len = outlen;
|
||||
cd = iconv_open (tocode, fromcode);
|
||||
if (cd == (iconv_t)(-1))
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("Conversion from %s to UTF-8 isn't supported\n"),
|
||||
quote (opt.locale));
|
||||
*out = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* iconv() has to work on an unescaped string */
|
||||
in_org = in;
|
||||
in_save = in = xstrndup(in, inlen);
|
||||
url_unescape(in);
|
||||
inlen = strlen(in);
|
||||
|
||||
len = outlen = inlen * 2;
|
||||
*out = s = xmalloc (outlen + 1);
|
||||
done = 0;
|
||||
|
||||
for (;;)
|
||||
@@ -164,6 +149,9 @@ do_conversion (iconv_t cd, char *in, size_t inlen, char **out)
|
||||
{
|
||||
*out = s;
|
||||
*(s + len - outlen - done) = '\0';
|
||||
xfree(in_save);
|
||||
iconv_close(cd);
|
||||
DEBUGP (("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -202,9 +190,35 @@ do_conversion (iconv_t cd, char *in, size_t inlen, char **out)
|
||||
}
|
||||
}
|
||||
|
||||
xfree(in_save);
|
||||
iconv_close(cd);
|
||||
DEBUGP (("converted '%s' (%s) -> '%s' (%s)\n", in_org, fromcode, *out, tocode));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Try converting string str from locale to UTF-8. Return a new string
|
||||
on success, or str on error or if conversion isn't needed. */
|
||||
const char *
|
||||
locale_to_utf8 (const char *str)
|
||||
{
|
||||
char *new;
|
||||
|
||||
/* That shouldn't happen, just in case */
|
||||
if (!opt.locale)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("locale_to_utf8: locale is unset\n"));
|
||||
opt.locale = find_locale ();
|
||||
}
|
||||
|
||||
if (!opt.locale || !c_strcasecmp (opt.locale, "utf-8"))
|
||||
return str;
|
||||
|
||||
if (do_conversion ("UTF-8", opt.locale, (char *) str, strlen ((char *) str), &new))
|
||||
return (const char *) new;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Try to "ASCII encode" UTF-8 host. Return the new domain on success or NULL
|
||||
on error. */
|
||||
char *
|
||||
@@ -256,22 +270,21 @@ 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 (!c_strcasecmp (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 unsigned char *p;
|
||||
for (p = (unsigned char *) str; *p; p++)
|
||||
if (*p > 127)
|
||||
{
|
||||
*new = strdup (str);
|
||||
return true;
|
||||
@@ -279,19 +292,13 @@ remote_to_utf8 (struct iri *i, const char *str, const char **new)
|
||||
return false;
|
||||
}
|
||||
|
||||
cd = iconv_open ("UTF-8", i->uri_encoding);
|
||||
if (cd == (iconv_t)(-1))
|
||||
return false;
|
||||
|
||||
if (do_conversion (cd, (char *) str, strlen ((char *) str), (char **) new))
|
||||
if (do_conversion ("UTF-8", iri->uri_encoding, (char *) str, strlen (str), (char **) new))
|
||||
ret = true;
|
||||
|
||||
iconv_close (cd);
|
||||
|
||||
/* Test if something was converted */
|
||||
if (!strcmp (str, *new))
|
||||
if (*new && !strcmp (str, *new))
|
||||
{
|
||||
xfree ((char *) *new);
|
||||
xfree (*new);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -325,10 +332,13 @@ struct iri *iri_dup (const struct iri *src)
|
||||
void
|
||||
iri_free (struct iri *i)
|
||||
{
|
||||
xfree_null (i->uri_encoding);
|
||||
xfree_null (i->content_encoding);
|
||||
xfree_null (i->orig_url);
|
||||
xfree (i);
|
||||
if (i)
|
||||
{
|
||||
xfree (i->uri_encoding);
|
||||
xfree (i->content_encoding);
|
||||
xfree (i->orig_url);
|
||||
xfree (i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set uri_encoding of struct iri i. If a remote encoding was specified, use
|
||||
@@ -341,7 +351,7 @@ set_uri_encoding (struct iri *i, char *charset, bool force)
|
||||
return;
|
||||
if (i->uri_encoding)
|
||||
{
|
||||
if (charset && !strcasecmp (i->uri_encoding, charset))
|
||||
if (charset && !c_strcasecmp (i->uri_encoding, charset))
|
||||
return;
|
||||
xfree (i->uri_encoding);
|
||||
}
|
||||
@@ -358,11 +368,10 @@ set_content_encoding (struct iri *i, char *charset)
|
||||
return;
|
||||
if (i->content_encoding)
|
||||
{
|
||||
if (charset && !strcasecmp (i->content_encoding, charset))
|
||||
if (charset && !c_strcasecmp (i->content_encoding, charset))
|
||||
return;
|
||||
xfree (i->content_encoding);
|
||||
}
|
||||
|
||||
i->content_encoding = charset ? xstrdup (charset) : NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ struct iri {
|
||||
|
||||
#ifdef ENABLE_IRI
|
||||
|
||||
# include <idna.h>
|
||||
# include <idn-free.h>
|
||||
|
||||
char *parse_charset (char *str);
|
||||
char *find_locale (void);
|
||||
bool check_encoding_name (char *encoding);
|
||||
@@ -62,6 +65,7 @@ extern struct iri dummy_iri;
|
||||
#define locale_to_utf8(str) (str)
|
||||
#define idn_encode(a,b) NULL
|
||||
#define idn_decode(str) NULL
|
||||
#define idn_free(str) ((void)0)
|
||||
#define remote_to_utf8(a,b,c) false
|
||||
#define iri_new() (&dummy_iri)
|
||||
#define iri_dup(a) (&dummy_iri)
|
||||
|
||||
55
src/log.c
55
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.
|
||||
@@ -72,7 +73,7 @@ as that of the covered work. */
|
||||
- Inhibiting output. When Wget receives SIGHUP, but redirecting
|
||||
the output fails, logging is inhibited. */
|
||||
|
||||
|
||||
|
||||
/* The file descriptor used for logging. This is NULL before log_init
|
||||
is called; logging functions log to stderr then. log_init sets it
|
||||
either to stderr or to a file pointer obtained from fopen(). If
|
||||
@@ -141,7 +142,7 @@ static int log_line_current = -1;
|
||||
static bool trailing_line;
|
||||
|
||||
static void check_redirect_output (void);
|
||||
|
||||
|
||||
#define ROT_ADVANCE(num) do { \
|
||||
if (++num >= SAVED_LOG_LINES) \
|
||||
num = 0; \
|
||||
@@ -155,11 +156,7 @@ static void
|
||||
free_log_line (int num)
|
||||
{
|
||||
struct log_ln *ln = log_lines + num;
|
||||
if (ln->malloced_line)
|
||||
{
|
||||
xfree (ln->malloced_line);
|
||||
ln->malloced_line = NULL;
|
||||
}
|
||||
xfree (ln->malloced_line);
|
||||
ln->content = NULL;
|
||||
}
|
||||
|
||||
@@ -264,7 +261,7 @@ saved_append (const char *s)
|
||||
s = end;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check X against opt.verbose and opt.quiet. The semantics is as
|
||||
follows:
|
||||
|
||||
@@ -278,6 +275,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: \
|
||||
@@ -309,6 +310,14 @@ get_log_fp (void)
|
||||
return stderr;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
get_progress_fp (void)
|
||||
{
|
||||
if (opt.show_progress == true)
|
||||
return stderr;
|
||||
return get_log_fp();
|
||||
}
|
||||
|
||||
/* Returns the file descriptor for the secondary log file. This is
|
||||
WARCLOGFP, except if called before log_init, in which case it
|
||||
returns stderr. This is useful in case someone calls a logging
|
||||
@@ -333,7 +342,7 @@ log_set_warc_log_fp (FILE * fp)
|
||||
{
|
||||
warclogfp = fp;
|
||||
}
|
||||
|
||||
|
||||
/* Log a literal string S. The string is logged as-is, without a
|
||||
newline appended. */
|
||||
|
||||
@@ -344,8 +353,14 @@ logputs (enum log_options o, const char *s)
|
||||
FILE *warcfp;
|
||||
|
||||
check_redirect_output ();
|
||||
if ((fp = get_log_fp ()) == NULL)
|
||||
if (o == LOG_PROGRESS)
|
||||
fp = get_progress_fp ();
|
||||
else
|
||||
fp = get_log_fp ();
|
||||
|
||||
if (fp == NULL)
|
||||
return;
|
||||
|
||||
warcfp = get_warc_log_fp ();
|
||||
CHECK_VERBOSE (o);
|
||||
|
||||
@@ -380,7 +395,7 @@ struct logvprintf_state {
|
||||
(An alternative approach would be to use va_copy, but that's not
|
||||
portable.) */
|
||||
|
||||
static bool
|
||||
static bool GCC_FORMAT_ATTR (2, 0)
|
||||
log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
@@ -446,8 +461,7 @@ log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
|
||||
FPUTS (write_ptr, fp);
|
||||
if (warcfp != NULL)
|
||||
FPUTS (write_ptr, warcfp);
|
||||
if (state->bigmsg)
|
||||
xfree (state->bigmsg);
|
||||
xfree (state->bigmsg);
|
||||
|
||||
flush:
|
||||
if (flush_log_p)
|
||||
@@ -536,6 +550,7 @@ logprintf (enum log_options o, const char *fmt, ...)
|
||||
CHECK_VERBOSE (o);
|
||||
|
||||
xzero (lpstate);
|
||||
errno = 0;
|
||||
do
|
||||
{
|
||||
va_start (args, fmt);
|
||||
@@ -543,7 +558,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);
|
||||
}
|
||||
@@ -575,7 +590,7 @@ debug_logprintf (const char *fmt, ...)
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_DEBUG */
|
||||
|
||||
|
||||
/* Open FILE and set up a logging stream. If FILE cannot be opened,
|
||||
exit with status of 1. */
|
||||
void
|
||||
@@ -587,7 +602,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
|
||||
@@ -670,7 +685,7 @@ log_dump_context (void)
|
||||
fflush (fp);
|
||||
fflush (warcfp);
|
||||
}
|
||||
|
||||
|
||||
/* String escape functions. */
|
||||
|
||||
/* Return the number of non-printable characters in SOURCE.
|
||||
@@ -842,9 +857,9 @@ log_cleanup (void)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < countof (ring); i++)
|
||||
xfree_null (ring[i].buffer);
|
||||
xfree (ring[i].buffer);
|
||||
}
|
||||
|
||||
|
||||
/* When SIGHUP or SIGUSR1 are received, the output is redirected
|
||||
elsewhere. Such redirection is only allowed once. */
|
||||
static enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
|
||||
@@ -871,7 +886,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 *);
|
||||
|
||||
|
||||
759
src/main.c
759
src/main.c
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -84,11 +85,11 @@ windows_main (char **exec_name)
|
||||
if (p)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ws_cleanup (void)
|
||||
{
|
||||
xfree ((char*)exec_name);
|
||||
xfree (exec_name);
|
||||
WSACleanup ();
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
@@ -366,8 +367,8 @@ static int old_percentage = -1;
|
||||
void
|
||||
ws_changetitle (const char *url)
|
||||
{
|
||||
xfree_null (title_buf);
|
||||
xfree_null (curr_url);
|
||||
xfree (title_buf);
|
||||
xfree (curr_url);
|
||||
title_buf = xmalloc (strlen (url) + 20);
|
||||
curr_url = xstrdup (url);
|
||||
old_percentage = -1;
|
||||
@@ -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,14 +470,14 @@ 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);
|
||||
set_sleep_mode ();
|
||||
SetConsoleCtrlHandler (ws_handler, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* run_with_timeout Windows implementation. */
|
||||
|
||||
/* Stack size 0 uses default thread stack-size (reserve+commit).
|
||||
@@ -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: */
|
||||
|
||||
92
src/netrc.c
92
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,57 +161,13 @@ 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
|
||||
# define xfree(p) do { free ((void *) (p)); p = NULL; } while (0)
|
||||
# define xstrdup strdup
|
||||
|
||||
# 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
|
||||
@@ -221,9 +183,9 @@ maybe_add_to_list (acc_t **newentry, acc_t **list)
|
||||
if (a && ! a->acc)
|
||||
{
|
||||
/* Free any allocated space. */
|
||||
xfree_null (a->host);
|
||||
xfree_null (a->acc);
|
||||
xfree_null (a->passwd);
|
||||
xfree (a->host);
|
||||
xfree (a->acc);
|
||||
xfree (a->passwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -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. */
|
||||
@@ -462,9 +424,9 @@ free_netrc(acc_t *l)
|
||||
while (l)
|
||||
{
|
||||
t = l->next;
|
||||
xfree_null (l->acc);
|
||||
xfree_null (l->passwd);
|
||||
xfree_null (l->host);
|
||||
xfree (l->acc);
|
||||
xfree (l->passwd);
|
||||
xfree (l->host);
|
||||
xfree (l);
|
||||
l = t;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
204
src/openssl.c
204
src/openssl.c
@@ -40,6 +40,11 @@ as that of the covered work. */
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/bio.h>
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "connect.h"
|
||||
@@ -86,9 +91,11 @@ init_prng (void)
|
||||
if (RAND_status ())
|
||||
return;
|
||||
|
||||
#ifdef HAVE_RAND_EGD
|
||||
/* Get random data from EGD if opt.egd_file was used. */
|
||||
if (opt.egd_file && *opt.egd_file)
|
||||
RAND_egd (opt.egd_file);
|
||||
#endif
|
||||
|
||||
if (RAND_status ())
|
||||
return;
|
||||
@@ -153,6 +160,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.
|
||||
|
||||
@@ -162,6 +172,15 @@ bool
|
||||
ssl_init (void)
|
||||
{
|
||||
SSL_METHOD const *meth;
|
||||
long ssl_options = 0;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000
|
||||
if (ssl_true_initialized == 0)
|
||||
{
|
||||
OPENSSL_config (NULL);
|
||||
ssl_true_initialized = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ssl_ctx)
|
||||
/* The SSL has already been initialized. */
|
||||
@@ -176,6 +195,12 @@ ssl_init (void)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000
|
||||
OPENSSL_load_builtin_modules();
|
||||
ENGINE_load_builtin_engines();
|
||||
CONF_modules_load_file(NULL, NULL,
|
||||
CONF_MFLAGS_DEFAULT_SECTION|CONF_MFLAGS_IGNORE_MISSING_FILE);
|
||||
#endif
|
||||
SSL_library_init ();
|
||||
SSL_load_error_strings ();
|
||||
SSLeay_add_all_algorithms ();
|
||||
@@ -183,21 +208,48 @@ ssl_init (void)
|
||||
|
||||
switch (opt.secure_protocol)
|
||||
{
|
||||
case secure_protocol_auto:
|
||||
meth = SSLv23_client_method ();
|
||||
break;
|
||||
#ifndef OPENSSL_NO_SSL2
|
||||
case secure_protocol_sslv2:
|
||||
meth = SSLv2_client_method ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_SSL3
|
||||
case secure_protocol_sslv3:
|
||||
meth = SSLv3_client_method ();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case secure_protocol_auto:
|
||||
case secure_protocol_pfs:
|
||||
meth = SSLv23_client_method ();
|
||||
ssl_options |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
|
||||
break;
|
||||
case secure_protocol_tlsv1:
|
||||
meth = TLSv1_client_method ();
|
||||
break;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10001000
|
||||
case secure_protocol_tlsv1_1:
|
||||
meth = TLSv1_1_client_method ();
|
||||
break;
|
||||
|
||||
case secure_protocol_tlsv1_2:
|
||||
meth = TLSv1_2_client_method ();
|
||||
break;
|
||||
#else
|
||||
case secure_protocol_tlsv1_1:
|
||||
logprintf (LOG_NOTQUIET, _("Your OpenSSL version is too old to support TLSv1.1\n"));
|
||||
goto error;
|
||||
|
||||
case secure_protocol_tlsv1_2:
|
||||
logprintf (LOG_NOTQUIET, _("Your OpenSSL version is too old to support TLSv1.2\n"));
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
default:
|
||||
logprintf (LOG_NOTQUIET, _("OpenSSL: unimplemented 'secure-protocol' option value %d\n"), opt.secure_protocol);
|
||||
logprintf (LOG_NOTQUIET, _("Please report this issue to bug-wget@gnu.org\n"));
|
||||
abort ();
|
||||
}
|
||||
|
||||
@@ -207,9 +259,30 @@ ssl_init (void)
|
||||
if (!ssl_ctx)
|
||||
goto error;
|
||||
|
||||
if (ssl_options)
|
||||
SSL_CTX_set_options (ssl_ctx, ssl_options);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (opt.crl_file)
|
||||
{
|
||||
X509_STORE *store = SSL_CTX_get_cert_store (ssl_ctx);
|
||||
X509_LOOKUP *lookup;
|
||||
|
||||
if (!(lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ()))
|
||||
|| (!X509_load_crl_file (lookup, opt.crl_file, X509_FILETYPE_PEM)))
|
||||
goto error;
|
||||
|
||||
X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
|
||||
}
|
||||
|
||||
/* SSL_VERIFY_NONE instructs OpenSSL not to abort SSL_connect if the
|
||||
certificate is invalid. We verify the certificate separately in
|
||||
ssl_check_certificate, which provides much better diagnostics
|
||||
@@ -251,28 +324,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 +413,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;
|
||||
@@ -326,7 +425,7 @@ openssl_errstr (int fd, void *arg)
|
||||
return NULL;
|
||||
|
||||
/* Get rid of previous contents of ctx->last_error, if any. */
|
||||
xfree_null (ctx->last_error);
|
||||
xfree (ctx->last_error);
|
||||
|
||||
/* Iterate over OpenSSL's error stack and accumulate errors in the
|
||||
last_error buffer, separated by "; ". This is better than using
|
||||
@@ -370,7 +469,7 @@ openssl_close (int fd, void *arg)
|
||||
|
||||
SSL_shutdown (conn);
|
||||
SSL_free (conn);
|
||||
xfree_null (ctx->last_error);
|
||||
xfree (ctx->last_error);
|
||||
xfree (ctx);
|
||||
|
||||
close (fd);
|
||||
@@ -386,6 +485,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 +510,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 +525,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 +538,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 || SSL_state(conn) != SSL_ST_OK)
|
||||
goto error;
|
||||
|
||||
ctx = xnew0 (struct openssl_transport_context);
|
||||
@@ -441,6 +561,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;
|
||||
@@ -489,6 +610,27 @@ pattern_match (const char *pattern, const char *string)
|
||||
return *n == '\0';
|
||||
}
|
||||
|
||||
static char *_get_rfc2253_formatted (X509_NAME *name)
|
||||
{
|
||||
int len;
|
||||
char *out = NULL;
|
||||
BIO* b;
|
||||
|
||||
if ((b = BIO_new (BIO_s_mem ())))
|
||||
{
|
||||
if (X509_NAME_print_ex (b, name, 0, XN_FLAG_RFC2253) >= 0
|
||||
&& (len = BIO_number_written (b)) > 0)
|
||||
{
|
||||
out = xmalloc (len + 1);
|
||||
BIO_read (b, out, len);
|
||||
out[len] = 0;
|
||||
}
|
||||
BIO_free (b);
|
||||
}
|
||||
|
||||
return out ? out : xstrdup("");
|
||||
}
|
||||
|
||||
/* Verify the validity of the certificate presented by the server.
|
||||
Also check that the "common name" of the server, as presented by
|
||||
its certificate, corresponds to HOST. (HOST typically comes from
|
||||
@@ -532,23 +674,25 @@ ssl_check_certificate (int fd, const char *host)
|
||||
|
||||
IF_DEBUG
|
||||
{
|
||||
char *subject = X509_NAME_oneline (X509_get_subject_name (cert), 0, 0);
|
||||
char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
|
||||
char *subject = _get_rfc2253_formatted (X509_get_subject_name (cert));
|
||||
char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert));
|
||||
DEBUGP (("certificate:\n subject: %s\n issuer: %s\n",
|
||||
quotearg_n_style (0, escape_quoting_style, subject),
|
||||
quotearg_n_style (1, escape_quoting_style, issuer)));
|
||||
OPENSSL_free (subject);
|
||||
OPENSSL_free (issuer);
|
||||
xfree (subject);
|
||||
xfree (issuer);
|
||||
}
|
||||
|
||||
vresult = SSL_get_verify_result (conn);
|
||||
if (vresult != X509_V_OK)
|
||||
{
|
||||
char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), 0, 0);
|
||||
char *issuer = _get_rfc2253_formatted (X509_get_issuer_name (cert));
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("%s: cannot verify %s's certificate, issued by %s:\n"),
|
||||
severity, quotearg_n_style (0, escape_quoting_style, host),
|
||||
quote_n (1, issuer));
|
||||
xfree(issuer);
|
||||
|
||||
/* Try to print more user-friendly (and translated) messages for
|
||||
the frequent verification errors. */
|
||||
switch (vresult)
|
||||
@@ -634,7 +778,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;
|
||||
@@ -644,7 +788,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
}
|
||||
}
|
||||
}
|
||||
sk_GENERAL_NAME_free (subjectAltNames);
|
||||
sk_GENERAL_NAME_pop_free(subjectAltNames, GENERAL_NAME_free);
|
||||
if (host_in_octet_string)
|
||||
ASN1_OCTET_STRING_free(host_in_octet_string);
|
||||
|
||||
@@ -657,7 +801,7 @@ ssl_check_certificate (int fd, const char *host)
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (alt_name_checked == false)
|
||||
{
|
||||
/* Test commomName */
|
||||
@@ -698,7 +842,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\
|
||||
|
||||
310
src/options.h
310
src/options.h
@@ -31,237 +31,245 @@ 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 */
|
||||
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. */
|
||||
int 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_tlsv1_1,
|
||||
secure_protocol_tlsv1_2,
|
||||
secure_protocol_pfs
|
||||
} secure_protocol; /* type of secure protocol to use. */
|
||||
bool check_cert; /* whether to validate the server's cert */
|
||||
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 *crl_file; /* file with CRLs */
|
||||
|
||||
|
||||
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,11 +282,11 @@ 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*/
|
||||
};
|
||||
|
||||
|
||||
276
src/progress.c
276
src/progress.c
@@ -36,38 +36,41 @@ as that of the covered work. */
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_WCHAR_H
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
#include <wchar.h>
|
||||
#include <mbiter.h>
|
||||
|
||||
#include "progress.h"
|
||||
#include "utils.h"
|
||||
#include "retr.h"
|
||||
#include "c-strcase.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 *);
|
||||
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 *);
|
||||
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 *);
|
||||
static void bar_finish (void *, double);
|
||||
static void bar_set_params (const char *);
|
||||
static void bar_set_params (char *);
|
||||
|
||||
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;
|
||||
@@ -109,7 +112,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,7 +154,7 @@ 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. */
|
||||
if (output_redirected)
|
||||
@@ -161,7 +164,7 @@ progress_create (wgint initial, wgint total)
|
||||
output_redirected = 0;
|
||||
}
|
||||
|
||||
return current_impl->create (initial, total);
|
||||
return current_impl->create (f_download, initial, total);
|
||||
}
|
||||
|
||||
/* Return true if the progress gauge is "interactive", i.e. if it can
|
||||
@@ -170,7 +173,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;
|
||||
}
|
||||
@@ -182,6 +185,7 @@ void
|
||||
progress_update (void *progress, wgint howmuch, double dltime)
|
||||
{
|
||||
current_impl->update (progress, howmuch, dltime);
|
||||
current_impl->draw (progress);
|
||||
}
|
||||
|
||||
/* Tell the progress gauge to clean up. Calling this will free the
|
||||
@@ -192,7 +196,7 @@ progress_finish (void *progress, double dltime)
|
||||
{
|
||||
current_impl->finish (progress, dltime);
|
||||
}
|
||||
|
||||
|
||||
/* Dot-printing. */
|
||||
|
||||
struct dot_progress {
|
||||
@@ -204,6 +208,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 +218,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 +242,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 +294,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 +311,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 +328,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 +336,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,6 +347,14 @@ 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)
|
||||
{
|
||||
struct dot_progress *dp = progress;
|
||||
int dot_bytes = opt.dot_bytes;
|
||||
@@ -349,16 +362,15 @@ dot_update (void *progress, wgint howmuch, double dltime)
|
||||
|
||||
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 +378,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 +397,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 +419,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;
|
||||
@@ -416,7 +428,7 @@ dot_set_params (const char *params)
|
||||
return;
|
||||
|
||||
/* We use this to set the retrieval style. */
|
||||
if (!strcasecmp (params, "default"))
|
||||
if (!c_strcasecmp (params, "default"))
|
||||
{
|
||||
/* Default style: 1K dots, 10 dots in a cluster, 50 dots in a
|
||||
line. */
|
||||
@@ -424,7 +436,7 @@ dot_set_params (const char *params)
|
||||
opt.dot_spacing = 10;
|
||||
opt.dots_in_line = 50;
|
||||
}
|
||||
else if (!strcasecmp (params, "binary"))
|
||||
else if (!c_strcasecmp (params, "binary"))
|
||||
{
|
||||
/* "Binary" retrieval: 8K dots, 16 dots in a cluster, 48 dots
|
||||
(384K) in a line. */
|
||||
@@ -432,7 +444,7 @@ dot_set_params (const char *params)
|
||||
opt.dot_spacing = 16;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (params, "mega"))
|
||||
else if (!c_strcasecmp (params, "mega"))
|
||||
{
|
||||
/* "Mega" retrieval, for retrieving very long files; each dot is
|
||||
64K, 8 dots in a cluster, 6 clusters (3M) in a line. */
|
||||
@@ -440,7 +452,7 @@ dot_set_params (const char *params)
|
||||
opt.dot_spacing = 8;
|
||||
opt.dots_in_line = 48;
|
||||
}
|
||||
else if (!strcasecmp (params, "giga"))
|
||||
else if (!c_strcasecmp (params, "giga"))
|
||||
{
|
||||
/* "Giga" retrieval, for retrieving very very *very* long files;
|
||||
each dot is 1M, 8 dots in a cluster, 4 clusters (32M) in a
|
||||
@@ -454,7 +466,7 @@ dot_set_params (const char *params)
|
||||
_("Invalid dot style specification %s; leaving unchanged.\n"),
|
||||
quote (params));
|
||||
}
|
||||
|
||||
|
||||
/* "Thermometer" (bar) progress. */
|
||||
|
||||
/* Assumed screen width if we can't find the real value. */
|
||||
@@ -495,6 +507,7 @@ static volatile sig_atomic_t received_sigwinch;
|
||||
#define ETA_REFRESH_INTERVAL 0.99
|
||||
|
||||
struct bar_progress {
|
||||
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
|
||||
@@ -505,6 +518,7 @@ struct bar_progress {
|
||||
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
|
||||
@@ -551,7 +565,7 @@ static void create_image (struct bar_progress *, 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 +576,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. */
|
||||
@@ -595,8 +610,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,6 +623,13 @@ bar_update (void *progress, wgint howmuch, double dltime)
|
||||
bp->total_length = bp->initial_length + bp->count;
|
||||
|
||||
update_speed_ring (bp, howmuch, dltime);
|
||||
}
|
||||
|
||||
static void
|
||||
bar_draw (void *progress)
|
||||
{
|
||||
bool force_screen_update = false;
|
||||
struct bar_progress *bp = progress;
|
||||
|
||||
/* If SIGWINCH (the window size change signal) been received,
|
||||
determine the new screen size and update the screen. */
|
||||
@@ -628,13 +650,13 @@ bar_update (void *progress, wgint howmuch, double dltime)
|
||||
received_sigwinch = 0;
|
||||
}
|
||||
|
||||
if (dltime - bp->last_screen_update < REFRESH_INTERVAL && !force_screen_update)
|
||||
if (bp->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);
|
||||
create_image (bp, bp->dltime, false);
|
||||
display_image (bp->buffer);
|
||||
bp->last_screen_update = dltime;
|
||||
bp->last_screen_update = bp->dltime;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -650,7 +672,8 @@ bar_finish (void *progress, double dltime)
|
||||
create_image (bp, dltime, true);
|
||||
display_image (bp->buffer);
|
||||
|
||||
logputs (LOG_VERBOSE, "\n\n");
|
||||
logputs (LOG_VERBOSE, "\n");
|
||||
logputs (LOG_PROGRESS, "\n");
|
||||
|
||||
xfree (bp->buffer);
|
||||
xfree (bp);
|
||||
@@ -791,8 +814,39 @@ count_cols (const char *mbs)
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
|
||||
static int
|
||||
cols_to_bytes (const char *mbs, const int cols, int *ncols)
|
||||
{
|
||||
int p_cols = 0, bytes = 0;
|
||||
mbchar_t mbc;
|
||||
mbi_iterator_t iter;
|
||||
mbi_init (iter, mbs, strlen(mbs));
|
||||
while (p_cols < cols && mbi_avail (iter))
|
||||
{
|
||||
mbc = mbi_cur (iter);
|
||||
p_cols += mb_width (mbc);
|
||||
/* The multibyte character has exceeded the total number of columns we
|
||||
* have available. The remaining bytes will be padded with a space. */
|
||||
if (p_cols > cols)
|
||||
{
|
||||
p_cols -= mb_width (mbc);
|
||||
break;
|
||||
}
|
||||
bytes += mb_len (mbc);
|
||||
mbi_advance (iter);
|
||||
}
|
||||
*ncols = p_cols;
|
||||
return bytes;
|
||||
}
|
||||
#else
|
||||
# define count_cols(mbs) ((int)(strlen(mbs)))
|
||||
static int count_cols (const char *mbs) { return (int) strlen(mbs); }
|
||||
static int
|
||||
cols_to_bytes (const char *mbs _GL_UNUSED, const int cols, int *ncols)
|
||||
{
|
||||
*ncols = cols;
|
||||
return cols;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
@@ -800,7 +854,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)
|
||||
@@ -842,26 +896,20 @@ get_eta (int *bcd)
|
||||
are confused when they see strchr (s, '\0') in the code. */
|
||||
#define move_to_end(s) s = strchr (s, '\0');
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a, b) ((a) >= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
static void
|
||||
create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
{
|
||||
const int MAX_FILENAME_COLS = bp->width / 4;
|
||||
char *p = bp->buffer;
|
||||
wgint size = bp->initial_length + bp->count;
|
||||
|
||||
const char *size_grouped = with_thousand_seps (size);
|
||||
int size_grouped_len = count_cols (size_grouped);
|
||||
/* Difference between num cols and num bytes: */
|
||||
int size_grouped_diff = strlen (size_grouped) - size_grouped_len;
|
||||
int size_grouped_pad; /* Used to pad the field width for size_grouped. */
|
||||
|
||||
struct bar_progress_hist *hist = &bp->hist;
|
||||
int orig_filename_cols = count_cols (bp->f_download);
|
||||
|
||||
/* 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,24 +918,70 @@ 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_COLS chars + 1
|
||||
"xx% " or "100%" - percentage - 4 chars
|
||||
"[]" - 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_COLS + 1
|
||||
#define PROGRESS_PERCENT_LEN 4
|
||||
#define PROGRESS_DECORAT_LEN 2
|
||||
#define PROGRESS_FILESIZE_LEN 7 + 1
|
||||
#define PROGRESS_DWNLOAD_RATE 8 + 1
|
||||
#define PROGRESS_ETA_LEN 14
|
||||
|
||||
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. */
|
||||
int bytes_cols_diff = 0;
|
||||
int cols_diff;
|
||||
const char *down_size;
|
||||
|
||||
if (progress_size < 5)
|
||||
progress_size = 0;
|
||||
|
||||
if (orig_filename_cols <= MAX_FILENAME_COLS)
|
||||
{
|
||||
int padding = MAX_FILENAME_COLS - orig_filename_cols;
|
||||
sprintf (p, "%s ", bp->f_download);
|
||||
p += orig_filename_cols + 1;
|
||||
for (;padding;padding--)
|
||||
*p++ = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset_cols;
|
||||
int bytes_in_filename, offset_bytes, col;
|
||||
int *cols_ret = &col;
|
||||
int padding;
|
||||
|
||||
#define MIN_SCROLL_TEXT 5
|
||||
if ((orig_filename_cols > MAX_FILENAME_COLS + MIN_SCROLL_TEXT) &&
|
||||
!opt.noscroll &&
|
||||
!done)
|
||||
offset_cols = ((int) bp->tick) % (orig_filename_cols - MAX_FILENAME_COLS + 1);
|
||||
else
|
||||
offset_cols = 0;
|
||||
offset_bytes = cols_to_bytes (bp->f_download, offset_cols, cols_ret);
|
||||
bytes_in_filename = cols_to_bytes (bp->f_download + offset_bytes,
|
||||
MAX_FILENAME_COLS,
|
||||
cols_ret);
|
||||
memcpy (p, bp->f_download + offset_bytes, bytes_in_filename);
|
||||
p += bytes_in_filename;
|
||||
padding = MAX_FILENAME_COLS - *cols_ret;
|
||||
for (;padding;padding--)
|
||||
*p++ = ' ';
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
/* "xx% " */
|
||||
if (bp->total_length > 0)
|
||||
{
|
||||
@@ -895,7 +989,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;
|
||||
@@ -961,16 +1055,23 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
|
||||
}
|
||||
*p++ = ']';
|
||||
|
||||
++bp->tick;
|
||||
}
|
||||
++bp->tick;
|
||||
|
||||
/* " 234,567,890" */
|
||||
sprintf (p, " %s", size_grouped);
|
||||
/* " 234.56M" */
|
||||
down_size = human_readable (size, 1000, 2);
|
||||
cols_diff = 7 - count_cols (down_size);
|
||||
while (cols_diff > 0)
|
||||
{
|
||||
*p++=' ';
|
||||
cols_diff--;
|
||||
}
|
||||
sprintf (p, " %s", down_size);
|
||||
move_to_end (p);
|
||||
/* Pad with spaces to 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 +1081,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 +1094,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,9 +1159,18 @@ 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 - bp->buffer - bytes_cols_diff < bp->width)
|
||||
*p++ = ' ';
|
||||
*p = '\0';
|
||||
|
||||
/* 2014-11-14 Darshit Shah <darnir@gmail.com>
|
||||
* Assert that the length of the progress bar is lesser than the size of the
|
||||
* screen with which we are dealing. This assertion *MUST* always be removed
|
||||
* from the release code since we do not want Wget to crash and burn when the
|
||||
* assertion fails. Instead Wget should continue downloading and display a
|
||||
* horrible and irritating progress bar that spams the screen with newlines.
|
||||
*/
|
||||
assert (count_cols (bp->buffer) <= bp->width + 1);
|
||||
}
|
||||
|
||||
/* Print the contents of the buffer as a one-line ASCII "image" so
|
||||
@@ -1070,21 +1180,29 @@ 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
|
||||
if (((opt.lfilename && opt.show_progress != 1)
|
||||
#ifdef HAVE_ISATTY
|
||||
/* The progress bar doesn't make sense if the output is not a
|
||||
TTY -- when logging to file, it is better to review the
|
||||
@@ -1112,7 +1230,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);
|
||||
|
||||
@@ -291,7 +291,7 @@ windows_resolution (void)
|
||||
return 10; /* according to MSDN */
|
||||
}
|
||||
#endif /* PTIMER_WINDOWS */
|
||||
|
||||
|
||||
/* The code below this point is independent of timer implementation. */
|
||||
|
||||
struct ptimer {
|
||||
|
||||
@@ -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);
|
||||
|
||||
101
src/recur.c
101
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.
|
||||
@@ -50,7 +50,7 @@ as that of the covered work. */
|
||||
#include "html-url.h"
|
||||
#include "css-url.h"
|
||||
#include "spider.h"
|
||||
|
||||
|
||||
/* Functions for maintaining the URL queue. */
|
||||
|
||||
struct queue_element {
|
||||
@@ -159,7 +159,28 @@ url_dequeue (struct url_queue *queue, struct iri **i,
|
||||
xfree (qel);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void blacklist_add (struct hash_table *blacklist, const char *url)
|
||||
{
|
||||
char *url_unescaped = xstrdup (url);
|
||||
|
||||
url_unescape (url_unescaped);
|
||||
string_set_add (blacklist, url_unescaped);
|
||||
xfree (url_unescaped);
|
||||
}
|
||||
|
||||
static int blacklist_contains (struct hash_table *blacklist, const char *url)
|
||||
{
|
||||
char *url_unescaped = xstrdup(url);
|
||||
int ret;
|
||||
|
||||
url_unescape (url_unescaped);
|
||||
ret = string_set_contains (blacklist, url_unescaped);
|
||||
xfree (url_unescaped);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool download_child_p (const struct urlpos *, struct url *, int,
|
||||
struct url *, struct hash_table *, struct iri *);
|
||||
static bool descend_redirect_p (const char *, struct url *, int,
|
||||
@@ -220,7 +241,7 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
just URL so we enqueue the canonical form of the URL. */
|
||||
url_enqueue (queue, i, xstrdup (start_url_parsed->url), NULL, 0, true,
|
||||
false);
|
||||
string_set_add (blacklist, start_url_parsed->url);
|
||||
blacklist_add (blacklist, start_url_parsed->url);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -253,25 +274,22 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
the second time. */
|
||||
if (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
|
||||
@@ -314,7 +332,7 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
else
|
||||
/* Make sure that the old pre-redirect form gets
|
||||
blacklisted. */
|
||||
string_set_add (blacklist, url);
|
||||
blacklist_add (blacklist, url);
|
||||
}
|
||||
|
||||
xfree (url);
|
||||
@@ -325,7 +343,7 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
xfree (url);
|
||||
url = xstrdup (url_parsed->url);
|
||||
}
|
||||
url_free(url_parsed);
|
||||
url_free (url_parsed);
|
||||
}
|
||||
|
||||
if (opt.spider)
|
||||
@@ -407,7 +425,7 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
/* We blacklist the URL we have enqueued, because we
|
||||
don't want to enqueue (and hence download) the
|
||||
same URL twice. */
|
||||
string_set_add (blacklist, child->url->url);
|
||||
blacklist_add (blacklist, child->url->url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,8 +461,8 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
}
|
||||
|
||||
xfree (url);
|
||||
xfree_null (referer);
|
||||
xfree_null (file);
|
||||
xfree (referer);
|
||||
xfree (file);
|
||||
iri_free (i);
|
||||
}
|
||||
|
||||
@@ -460,7 +478,7 @@ retrieve_tree (struct url *start_url_parsed, struct iri *pi)
|
||||
{
|
||||
iri_free (d6);
|
||||
xfree (d1);
|
||||
xfree_null (d2);
|
||||
xfree (d2);
|
||||
}
|
||||
}
|
||||
url_queue_delete (queue);
|
||||
@@ -494,7 +512,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
|
||||
|
||||
DEBUGP (("Deciding whether to enqueue \"%s\".\n", url));
|
||||
|
||||
if (string_set_contains (blacklist, url))
|
||||
if (blacklist_contains (blacklist, url))
|
||||
{
|
||||
if (opt.spider)
|
||||
{
|
||||
@@ -508,15 +526,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 +547,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 +668,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));
|
||||
@@ -664,7 +691,7 @@ download_child_p (const struct urlpos *upos, struct url *parent, int depth,
|
||||
if (!res_match_path (specs, u->path))
|
||||
{
|
||||
DEBUGP (("Not following %s because robots.txt forbids it.\n", url));
|
||||
string_set_add (blacklist, url);
|
||||
blacklist_add (blacklist, url);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -706,12 +733,14 @@ descend_redirect_p (const char *redirected, struct url *orig_parsed, int depth,
|
||||
success = download_child_p (upos, orig_parsed, depth,
|
||||
start_url_parsed, blacklist, iri);
|
||||
|
||||
if (success)
|
||||
blacklist_add (blacklist, upos->url->url);
|
||||
else
|
||||
DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));
|
||||
|
||||
url_free (new_parsed);
|
||||
xfree (upos);
|
||||
|
||||
if (!success)
|
||||
DEBUGP (("Redirection \"%s\" failed the test.\n", redirected));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
29
src/res.c
29
src/res.c
@@ -81,6 +81,7 @@ as that of the covered work. */
|
||||
#include "url.h"
|
||||
#include "retr.h"
|
||||
#include "res.h"
|
||||
#include "c-strcase.h"
|
||||
|
||||
#ifdef TESTING
|
||||
#include "test.h"
|
||||
@@ -97,7 +98,7 @@ struct robot_specs {
|
||||
int size;
|
||||
struct path_info *paths;
|
||||
};
|
||||
|
||||
|
||||
/* Parsing the robot spec. */
|
||||
|
||||
/* Check whether AGENT (a string of length LENGTH) equals "wget" or
|
||||
@@ -403,10 +404,10 @@ free_specs (struct robot_specs *specs)
|
||||
int i;
|
||||
for (i = 0; i < specs->count; i++)
|
||||
xfree (specs->paths[i].path);
|
||||
xfree_null (specs->paths);
|
||||
xfree (specs->paths);
|
||||
xfree (specs);
|
||||
}
|
||||
|
||||
|
||||
/* Matching of a path according to the specs. */
|
||||
|
||||
/* If C is '%' and (ptr[1], ptr[2]) form a hexadecimal number, and if
|
||||
@@ -471,7 +472,7 @@ res_match_path (const struct robot_specs *specs, const char *path)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Registering the specs. */
|
||||
|
||||
static struct hash_table *registered_specs;
|
||||
@@ -521,7 +522,7 @@ res_get_specs (const char *host, int port)
|
||||
return NULL;
|
||||
return hash_table_get (registered_specs, hp);
|
||||
}
|
||||
|
||||
|
||||
/* Loading the robots file. */
|
||||
|
||||
#define RES_SPECS_LOCATION "/robots.txt"
|
||||
@@ -578,11 +579,10 @@ res_retrieve_file (const char *url, char **file, struct iri *iri)
|
||||
allocated the file name, deallocate is here so that the
|
||||
caller doesn't have to worry about it. */
|
||||
xfree (*file);
|
||||
*file = NULL;
|
||||
}
|
||||
return err == RETROK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
is_robots_txt_url (const char *url)
|
||||
{
|
||||
@@ -593,7 +593,7 @@ is_robots_txt_url (const char *url)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
res_cleanup (void)
|
||||
{
|
||||
@@ -611,15 +611,15 @@ res_cleanup (void)
|
||||
registered_specs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
|
||||
185
src/retr.c
185
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,6 +37,9 @@ as that of the covered work. */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef VMS
|
||||
# include <unixio.h> /* For delete(). */
|
||||
#endif
|
||||
|
||||
#include "exits.h"
|
||||
#include "utils.h"
|
||||
@@ -67,7 +70,7 @@ FILE *output_stream;
|
||||
/* Whether output_document is a regular file we can manipulate,
|
||||
i.e. not `-' or a device file. */
|
||||
bool output_stream_regular;
|
||||
|
||||
|
||||
static struct {
|
||||
wgint chunk_bytes;
|
||||
double chunk_start;
|
||||
@@ -133,16 +136,12 @@ limit_bandwidth (wgint bytes, struct ptimer *timer)
|
||||
limit_data.chunk_start = ptimer_read (timer);
|
||||
}
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(i, j) ((i) <= (j) ? (i) : (j))
|
||||
#endif
|
||||
|
||||
/* Write data in BUF to OUT. However, if *SKIP is non-zero, skip that
|
||||
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 +222,8 @@ 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 +259,18 @@ 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)
|
||||
{
|
||||
const char *filename_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);
|
||||
if (opt.dir_prefix)
|
||||
filename_progress = downloaded_filename + strlen (opt.dir_prefix) + 1;
|
||||
else
|
||||
filename_progress = downloaded_filename;
|
||||
progress = progress_create (filename_progress, start, start + toread);
|
||||
progress_interactive = progress_interactive_p (progress);
|
||||
}
|
||||
|
||||
@@ -374,9 +379,11 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
int write_res;
|
||||
|
||||
sum_read += ret;
|
||||
int write_res = write_data (out, out2, dlbuf, ret, &skip, &sum_written);
|
||||
if (write_res != 0)
|
||||
write_res = write_data (out, out2, dlbuf, ret, &skip, &sum_written);
|
||||
if (write_res < 0)
|
||||
{
|
||||
ret = (write_res == -3) ? -3 : -2;
|
||||
goto out;
|
||||
@@ -408,7 +415,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
|
||||
@@ -430,11 +437,11 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
if (qtywritten)
|
||||
*qtywritten += sum_written;
|
||||
|
||||
free (dlbuf);
|
||||
xfree (dlbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Read a hunk of data from FD, up until a terminator. The hunk is
|
||||
limited by whatever the TERMINATOR callback chooses as its
|
||||
terminator. For example, if terminator stops at newline, the hunk
|
||||
@@ -539,7 +546,7 @@ fd_read_hunk (int fd, hunk_terminator_t terminator, long sizehint, long maxsize)
|
||||
rdlen = fd_read (fd, hunk + tail, remain, 0);
|
||||
if (rdlen < 0)
|
||||
{
|
||||
xfree_null (hunk);
|
||||
xfree (hunk);
|
||||
return NULL;
|
||||
}
|
||||
tail += rdlen;
|
||||
@@ -584,7 +591,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)
|
||||
@@ -611,7 +618,7 @@ fd_read_line (int fd)
|
||||
{
|
||||
return fd_read_hunk (fd, line_terminator, 128, FD_READ_LINE_MAX);
|
||||
}
|
||||
|
||||
|
||||
/* Return a printed representation of the download rate, along with
|
||||
the units appropriate for the download speed. */
|
||||
|
||||
@@ -646,7 +653,7 @@ calc_rate (wgint bytes, double secs, int *units)
|
||||
{
|
||||
double dlrate;
|
||||
double bibyte = 1000.0;
|
||||
|
||||
|
||||
if (!opt.report_bps)
|
||||
bibyte = 1024.0;
|
||||
|
||||
@@ -675,22 +682,25 @@ calc_rate (wgint bytes, double secs, int *units)
|
||||
|
||||
return dlrate;
|
||||
}
|
||||
|
||||
|
||||
#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)
|
||||
|
||||
@@ -718,9 +728,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)
|
||||
@@ -753,7 +764,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
pi->utf8_encode = false;
|
||||
|
||||
/* Parse the proxy URL. */
|
||||
proxy_url = url_parse (proxy, &up_error_code, NULL, true);
|
||||
proxy_url = url_parse (proxy, &up_error_code, pi, true);
|
||||
if (!proxy_url)
|
||||
{
|
||||
char *error = url_error (proxy, up_error_code);
|
||||
@@ -761,7 +772,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 +781,12 @@ 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;
|
||||
}
|
||||
iri_free(pi);
|
||||
xfree (proxy);
|
||||
}
|
||||
|
||||
if (u->scheme == SCHEME_HTTP
|
||||
@@ -822,8 +835,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
|
||||
assert (mynewloc != NULL);
|
||||
|
||||
if (local_file)
|
||||
xfree (local_file);
|
||||
xfree (local_file);
|
||||
|
||||
/* The HTTP specs only allow absolute URLs to appear in
|
||||
redirects, but a ton of boneheaded webservers and CGIs out
|
||||
@@ -837,7 +849,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
the content encoding. */
|
||||
iri->utf8_encode = opt.enable_iri;
|
||||
set_content_encoding (iri, NULL);
|
||||
xfree_null (iri->orig_url);
|
||||
xfree (iri->orig_url);
|
||||
|
||||
/* Now, see if this new location makes sense. */
|
||||
newloc_parsed = url_parse (mynewloc, &up_error_code, iri, true);
|
||||
@@ -853,7 +865,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 +887,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,15 +906,19 @@ 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
xfree(mynewloc);
|
||||
}
|
||||
|
||||
/* Try to not encode in UTF-8 if fetching failed */
|
||||
if (!(*dt & RETROKF) && iri->utf8_encode)
|
||||
@@ -916,6 +932,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
if (u)
|
||||
{
|
||||
DEBUGP (("[IRI fallbacking to non-utf8 for %s\n", quote (url)));
|
||||
xfree (url);
|
||||
url = xstrdup (u->url);
|
||||
iri_fallbacked = 1;
|
||||
goto redirected;
|
||||
@@ -941,7 +958,7 @@ retrieve_url (struct url * orig_parsed, const char *origurl, char **file,
|
||||
if (file)
|
||||
*file = local_file ? local_file : NULL;
|
||||
else
|
||||
xfree_null (local_file);
|
||||
xfree (local_file);
|
||||
|
||||
if (orig_parsed != u)
|
||||
{
|
||||
@@ -962,7 +979,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 +1013,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)
|
||||
{
|
||||
@@ -1022,12 +1038,11 @@ 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;
|
||||
xfree_null (iri->orig_url);
|
||||
iri->orig_url = NULL;
|
||||
xfree (iri->orig_url);
|
||||
|
||||
input_file = url_file;
|
||||
}
|
||||
@@ -1037,12 +1052,12 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
url_list = (html ? get_urls_html (input_file, NULL, NULL, iri)
|
||||
: get_urls_file (input_file));
|
||||
|
||||
xfree_null (url_file);
|
||||
xfree (url_file);
|
||||
|
||||
for (cur_url = url_list; cur_url; cur_url = cur_url->next, ++*count)
|
||||
{
|
||||
char *filename = NULL, *new_file = NULL;
|
||||
int dt;
|
||||
char *filename = NULL, *new_file = NULL, *proxy;
|
||||
int dt = 0;
|
||||
struct iri *tmpiri = iri_dup (iri);
|
||||
struct url *parsed_url = NULL;
|
||||
|
||||
@@ -1057,8 +1072,9 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
|
||||
parsed_url = url_parse (cur_url->url->url, NULL, tmpiri, true);
|
||||
|
||||
proxy = getproxy (cur_url->url);
|
||||
if ((opt.recursive || opt.page_requisites)
|
||||
&& (cur_url->url->scheme != SCHEME_FTP || getproxy (cur_url->url)))
|
||||
&& (cur_url->url->scheme != SCHEME_FTP || proxy))
|
||||
{
|
||||
int old_follow_ftp = opt.follow_ftp;
|
||||
|
||||
@@ -1076,6 +1092,7 @@ retrieve_from_file (const char *file, bool html, int *count)
|
||||
cur_url->url->url, &filename,
|
||||
&new_file, NULL, &dt, opt.recursive, tmpiri,
|
||||
true);
|
||||
xfree (proxy);
|
||||
|
||||
if (parsed_url)
|
||||
url_free (parsed_url);
|
||||
@@ -1090,8 +1107,8 @@ Removing file due to --delete-after in retrieve_from_file():\n"));
|
||||
dt &= ~RETROKF;
|
||||
}
|
||||
|
||||
xfree_null (new_file);
|
||||
xfree_null (filename);
|
||||
xfree (new_file);
|
||||
xfree (filename);
|
||||
iri_free (tmpiri);
|
||||
}
|
||||
|
||||
@@ -1167,7 +1184,7 @@ free_urlpos (struct urlpos *l)
|
||||
struct urlpos *next = l->next;
|
||||
if (l->url)
|
||||
url_free (l->url);
|
||||
xfree_null (l->local_name);
|
||||
xfree (l->local_name);
|
||||
xfree (l);
|
||||
l = next;
|
||||
}
|
||||
@@ -1177,7 +1194,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 +1215,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 +1245,6 @@ getproxy (struct url *u)
|
||||
{
|
||||
char *proxy = NULL;
|
||||
char *rewritten_url;
|
||||
static char rewritten_storage[1024];
|
||||
|
||||
if (!opt.use_proxy)
|
||||
return NULL;
|
||||
@@ -1237,13 +1274,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. */
|
||||
@@ -1252,9 +1285,13 @@ bool
|
||||
url_uses_proxy (struct url * u)
|
||||
{
|
||||
bool ret;
|
||||
char *proxy;
|
||||
|
||||
if (!u)
|
||||
return false;
|
||||
ret = getproxy (u) != NULL;
|
||||
proxy = getproxy (u);
|
||||
ret = proxy != NULL;
|
||||
xfree (proxy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ as that of the covered work. */
|
||||
|
||||
#include "url.h"
|
||||
|
||||
extern int numurls;
|
||||
|
||||
/* These global vars should be made static to retr.c and exported via
|
||||
functions! */
|
||||
extern SUM_SIZE_INT total_downloaded_bytes;
|
||||
@@ -50,7 +52,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);
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ 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)
|
||||
string_set_free (nonexisting_urls_set);
|
||||
}
|
||||
|
||||
|
||||
/* Remembers broken links. */
|
||||
void
|
||||
nonexisting_url (const char *url)
|
||||
@@ -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
|
||||
|
||||
38
src/test.c
38
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"
|
||||
|
||||
@@ -36,22 +41,22 @@ as that of the covered work. */
|
||||
#error "TESTING not set!!!"
|
||||
#endif
|
||||
|
||||
const char *test_parse_content_disposition();
|
||||
const char *test_subdir_p();
|
||||
const char *test_dir_matches_p();
|
||||
const char *test_commands_sorted();
|
||||
const char *test_cmd_spec_restrict_file_names();
|
||||
const char *test_path_simplify ();
|
||||
const char *test_append_uri_pathel();
|
||||
const char *test_are_urls_equal();
|
||||
const char *test_is_robots_txt_url();
|
||||
const char *test_parse_content_disposition(void);
|
||||
const char *test_subdir_p(void);
|
||||
const char *test_dir_matches_p(void);
|
||||
const char *test_commands_sorted(void);
|
||||
const char *test_cmd_spec_restrict_file_names(void);
|
||||
const char *test_path_simplify (void);
|
||||
const char *test_append_uri_pathel(void);
|
||||
const char *test_are_urls_equal(void);
|
||||
const char *test_is_robots_txt_url(void);
|
||||
|
||||
const char *program_argstring = "TEST";
|
||||
|
||||
int tests_run;
|
||||
|
||||
static const char *
|
||||
all_tests()
|
||||
all_tests(void)
|
||||
{
|
||||
mu_run_test (test_parse_content_disposition);
|
||||
mu_run_test (test_subdir_p);
|
||||
@@ -66,13 +71,21 @@ all_tests()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *program_name; /* Needed by lib/error.c. */
|
||||
const char *program_name; /* Needed by lib/error.c. */
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
main (int argc _GL_UNUSED, const 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
|
||||
*/
|
||||
|
||||
|
||||
282
src/url.c
282
src/url.c
@@ -41,6 +41,7 @@ as that of the covered work. */
|
||||
#include "utils.h"
|
||||
#include "url.h"
|
||||
#include "host.h" /* for is_valid_ipv6_address */
|
||||
#include "c-strcase.h"
|
||||
|
||||
#ifdef __VMS
|
||||
#include "vms.h"
|
||||
@@ -85,7 +86,7 @@ static struct scheme_data supported_schemes[] =
|
||||
/* Forward declarations: */
|
||||
|
||||
static bool path_simplify (enum url_scheme, char *);
|
||||
|
||||
|
||||
/* Support for escaping and unescaping of URL strings. */
|
||||
|
||||
/* Table of "reserved" and "unsafe" characters. Those terms are
|
||||
@@ -169,7 +170,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 */
|
||||
@@ -272,7 +273,7 @@ url_escape_allow_passthrough (const char *s)
|
||||
{
|
||||
return url_escape_1 (s, urlchr_unsafe, true);
|
||||
}
|
||||
|
||||
|
||||
/* Decide whether the char at position P needs to be encoded. (It is
|
||||
not enough to pass a single char *P because the function may need
|
||||
to inspect the surrounding context.)
|
||||
@@ -418,7 +419,7 @@ reencode_escapes (const char *s)
|
||||
assert (p2 - newstr == newlen);
|
||||
return newstr;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the scheme type if the scheme is supported, or
|
||||
SCHEME_INVALID if not. */
|
||||
|
||||
@@ -574,8 +575,8 @@ rewrite_shorthand_url (const char *url)
|
||||
goto http;
|
||||
|
||||
/* Turn "foo.bar.com:path" to "ftp://foo.bar.com/path". */
|
||||
ret = aprintf ("ftp://%s", url);
|
||||
ret[6 + (p - url)] = '/';
|
||||
if ((ret = aprintf ("ftp://%s", url)) != NULL)
|
||||
ret[6 + (p - url)] = '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -585,7 +586,7 @@ rewrite_shorthand_url (const char *url)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void split_path (const char *, char **, char **);
|
||||
|
||||
/* Like strpbrk, with the exception that it returns the pointer to the
|
||||
@@ -681,7 +682,6 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
char *user = NULL, *passwd = NULL;
|
||||
|
||||
const char *url_encoded = NULL;
|
||||
char *new_url = NULL;
|
||||
|
||||
int error_code;
|
||||
|
||||
@@ -695,26 +695,30 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
goto error;
|
||||
}
|
||||
|
||||
url_encoded = url;
|
||||
|
||||
if (iri && iri->utf8_encode)
|
||||
{
|
||||
char *new_url = NULL;
|
||||
|
||||
iri->utf8_encode = remote_to_utf8 (iri, iri->orig_url ? iri->orig_url : url, (const char **) &new_url);
|
||||
if (!iri->utf8_encode)
|
||||
new_url = NULL;
|
||||
else
|
||||
iri->orig_url = xstrdup (url);
|
||||
{
|
||||
xfree (iri->orig_url);
|
||||
iri->orig_url = xstrdup (url);
|
||||
url_encoded = reencode_escapes (new_url);
|
||||
if (url_encoded != new_url)
|
||||
xfree (new_url);
|
||||
percent_encode = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX XXX Could that change introduce (security) bugs ??? XXX XXX*/
|
||||
if (percent_encode)
|
||||
url_encoded = reencode_escapes (new_url ? new_url : url);
|
||||
else
|
||||
url_encoded = new_url ? new_url : url;
|
||||
url_encoded = reencode_escapes (url);
|
||||
|
||||
p = url_encoded;
|
||||
|
||||
if (new_url && url_encoded != new_url)
|
||||
xfree (new_url);
|
||||
|
||||
p += strlen (supported_schemes[scheme].leading_string);
|
||||
uname_b = p;
|
||||
p = url_skip_credentials (p);
|
||||
@@ -893,6 +897,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
{
|
||||
xfree (u->host);
|
||||
u->host = new;
|
||||
u->idn_allocated = true;
|
||||
host_modified = true;
|
||||
}
|
||||
}
|
||||
@@ -913,7 +918,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
u->url = url_string (u, URL_AUTH_SHOW);
|
||||
|
||||
if (url_encoded != url)
|
||||
xfree ((char *) url_encoded);
|
||||
xfree (url_encoded);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -928,7 +933,7 @@ url_parse (const char *url, int *error, struct iri *iri, bool percent_encode)
|
||||
error:
|
||||
/* Cleanup in case of error: */
|
||||
if (url_encoded && url_encoded != url)
|
||||
xfree ((char *) url_encoded);
|
||||
xfree (url_encoded);
|
||||
|
||||
/* Transmit the error code to the caller, if the caller wants to
|
||||
know. */
|
||||
@@ -953,7 +958,7 @@ url_error (const char *url, int error_code)
|
||||
|
||||
if ((p = strchr (scheme, ':')))
|
||||
*p = '\0';
|
||||
if (!strcasecmp (scheme, "https"))
|
||||
if (!c_strcasecmp (scheme, "https"))
|
||||
error = aprintf (_("HTTPS support not compiled in"));
|
||||
else
|
||||
error = aprintf (_(parse_errors[error_code]), quote (scheme));
|
||||
@@ -1169,22 +1174,31 @@ url_set_file (struct url *url, const char *newfile)
|
||||
void
|
||||
url_free (struct url *url)
|
||||
{
|
||||
xfree (url->host);
|
||||
xfree (url->path);
|
||||
xfree (url->url);
|
||||
if (url)
|
||||
{
|
||||
if (url->idn_allocated) {
|
||||
idn_free (url->host); /* A dummy if !defined(ENABLE_IRI) */
|
||||
url->host = NULL;
|
||||
}
|
||||
else
|
||||
xfree (url->host);
|
||||
|
||||
xfree_null (url->params);
|
||||
xfree_null (url->query);
|
||||
xfree_null (url->fragment);
|
||||
xfree_null (url->user);
|
||||
xfree_null (url->passwd);
|
||||
xfree (url->path);
|
||||
xfree (url->url);
|
||||
|
||||
xfree (url->dir);
|
||||
xfree (url->file);
|
||||
xfree (url->params);
|
||||
xfree (url->query);
|
||||
xfree (url->fragment);
|
||||
xfree (url->user);
|
||||
xfree (url->passwd);
|
||||
|
||||
xfree (url);
|
||||
xfree (url->dir);
|
||||
xfree (url->file);
|
||||
|
||||
xfree (url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Create all the necessary directories for PATH (a file). Calls
|
||||
make_directory internally. */
|
||||
int
|
||||
@@ -1236,7 +1250,7 @@ mkalldirs (const char *path)
|
||||
xfree (t);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Functions for constructing the file name out of URL components. */
|
||||
|
||||
/* A growable string structure, used by url_file_name and friends.
|
||||
@@ -1245,12 +1259,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 +1286,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 +1396,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 +1490,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 +1531,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 +1598,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);
|
||||
}
|
||||
|
||||
xfree (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 */
|
||||
|
||||
xfree (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;
|
||||
@@ -1619,7 +1706,7 @@ url_file_name (const struct url *u, char *replaced_filename)
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
|
||||
/* Resolve "." and ".." elements of PATH by destructively modifying
|
||||
PATH and return true if PATH has been modified, false otherwise.
|
||||
|
||||
@@ -1705,7 +1792,7 @@ path_simplify (enum url_scheme scheme, char *path)
|
||||
|
||||
return t != h;
|
||||
}
|
||||
|
||||
|
||||
/* Return the length of URL's path. Path is considered to be
|
||||
terminated by one or more of the ?query or ;params or #fragment,
|
||||
depending on the scheme. */
|
||||
@@ -1916,7 +2003,7 @@ uri_merge (const char *base, const char *link)
|
||||
|
||||
return merge;
|
||||
}
|
||||
|
||||
|
||||
#define APPEND(p, s) do { \
|
||||
int len = strlen (s); \
|
||||
memcpy (p, s, len); \
|
||||
@@ -1960,7 +2047,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);
|
||||
}
|
||||
@@ -2033,7 +2120,7 @@ url_string (const struct url *url, enum url_auth_mode auth_mode)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if scheme a is similar to scheme b.
|
||||
|
||||
Schemes are similar if they are equal. If SSL is supported, schemes
|
||||
@@ -2051,7 +2138,7 @@ schemes_are_similar_p (enum url_scheme a, enum url_scheme b)
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getchar_from_escaped_string (const char *str, char *c)
|
||||
{
|
||||
@@ -2112,7 +2199,7 @@ are_urls_equal (const char *u1, const char *u2)
|
||||
|
||||
return (*p == 0 && *q == 0 ? true : false);
|
||||
}
|
||||
|
||||
|
||||
#ifdef TESTING
|
||||
/* Debugging and testing support for path_simplify. */
|
||||
|
||||
@@ -2129,7 +2216,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 +2245,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 +2278,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 +2295,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 +2316,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 +2324,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 +2341,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 +2355,3 @@ test_are_urls_equal()
|
||||
/*
|
||||
* vim: et ts=2 sw=2
|
||||
*/
|
||||
|
||||
|
||||
29
src/url.h
29
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;
|
||||
@@ -79,12 +95,17 @@ struct url
|
||||
/* Username and password (unquoted). */
|
||||
char *user;
|
||||
char *passwd;
|
||||
|
||||
/* 'host' is allocated by idna_to_ascii_8z() via idn_encode().
|
||||
* Call 'idn_free()' to free this memory. */
|
||||
bool idn_allocated;
|
||||
};
|
||||
|
||||
/* Function declarations */
|
||||
|
||||
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);
|
||||
|
||||
360
src/utils.c
360
src/utils.c
@@ -64,8 +64,8 @@ as that of the covered work. */
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* For TIOCGWINSZ and friends: */
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#ifndef WINDOWS
|
||||
# include <sys/ioctl.h>
|
||||
# include <termios.h>
|
||||
#endif
|
||||
|
||||
@@ -100,7 +100,10 @@ as that of the covered work. */
|
||||
#include "test.h"
|
||||
#endif
|
||||
|
||||
static void
|
||||
#include "exits.h"
|
||||
#include "c-strcase.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 +126,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
|
||||
@@ -267,7 +270,7 @@ sepstring (const char *s)
|
||||
res[i + 1] = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Like sprintf, but prints into a string of sufficient size freshly
|
||||
allocated with malloc, which is returned. If unable to print due
|
||||
to invalid format, returns NULL. Inability to allocate needed
|
||||
@@ -349,6 +352,32 @@ aprintf (const char *fmt, ...)
|
||||
#endif /* not HAVE_VASPRINTF */
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
/* strlcpy() is a BSD function that sometimes is really handy.
|
||||
* It is the same as snprintf(dst,dstsize,"%s",src), but much faster. */
|
||||
|
||||
size_t
|
||||
strlcpy (char *dst, const char *src, size_t size)
|
||||
{
|
||||
const char *old = src;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (size)
|
||||
{
|
||||
while (--size)
|
||||
{
|
||||
if (!(*dst++ = *src++))
|
||||
return src - old - 1;
|
||||
}
|
||||
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
while (*src++);
|
||||
return src - old - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Concatenate the NULL-terminated list of string arguments into
|
||||
freshly allocated space. */
|
||||
|
||||
@@ -356,47 +385,30 @@ char *
|
||||
concat_strings (const char *str0, ...)
|
||||
{
|
||||
va_list args;
|
||||
int saved_lengths[5]; /* inspired by Apache's apr_pstrcat */
|
||||
char *ret, *p;
|
||||
const char *arg;
|
||||
size_t length = 0, pos = 0;
|
||||
char *s;
|
||||
|
||||
const char *next_str;
|
||||
int total_length = 0;
|
||||
size_t argcount;
|
||||
if (!str0)
|
||||
return NULL;
|
||||
|
||||
/* Calculate the length of and allocate the resulting string. */
|
||||
|
||||
argcount = 0;
|
||||
/* calculate the length of the resulting string */
|
||||
va_start (args, str0);
|
||||
for (next_str = str0; next_str != NULL; next_str = va_arg (args, char *))
|
||||
{
|
||||
int len = strlen (next_str);
|
||||
if (argcount < countof (saved_lengths))
|
||||
saved_lengths[argcount++] = len;
|
||||
total_length += len;
|
||||
}
|
||||
for (arg = str0; arg; arg = va_arg (args, const char *))
|
||||
length += strlen(arg);
|
||||
va_end (args);
|
||||
p = ret = xmalloc (total_length + 1);
|
||||
|
||||
/* Copy the strings into the allocated space. */
|
||||
s = xmalloc (length + 1);
|
||||
|
||||
argcount = 0;
|
||||
/* concatenate strings */
|
||||
va_start (args, str0);
|
||||
for (next_str = str0; next_str != NULL; next_str = va_arg (args, char *))
|
||||
{
|
||||
int len;
|
||||
if (argcount < countof (saved_lengths))
|
||||
len = saved_lengths[argcount++];
|
||||
else
|
||||
len = strlen (next_str);
|
||||
memcpy (p, next_str, len);
|
||||
p += len;
|
||||
}
|
||||
for (arg = str0; arg; arg = va_arg (args, const char *))
|
||||
pos += strlcpy(s + pos, arg, length - pos + 1);
|
||||
va_end (args);
|
||||
*p = '\0';
|
||||
|
||||
return ret;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* Format the provided time according to the specified format. The
|
||||
format is a string with format elements supported by strftime. */
|
||||
|
||||
@@ -430,7 +442,7 @@ datetime_str (time_t t)
|
||||
{
|
||||
return fmttime(t, "%Y-%m-%d %H:%M:%S");
|
||||
}
|
||||
|
||||
|
||||
/* The Windows versions of the following two functions are defined in
|
||||
mswindows.c. On MSDOS this function should never be called. */
|
||||
|
||||
@@ -471,7 +483,7 @@ fork_to_background (void)
|
||||
{
|
||||
/* parent, error */
|
||||
perror ("fork");
|
||||
exit (1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
else if (pid != 0)
|
||||
{
|
||||
@@ -479,20 +491,23 @@ 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 */
|
||||
|
||||
#endif /* def __VMS [else] */
|
||||
|
||||
|
||||
|
||||
/* "Touch" FILE, i.e. make its mtime ("modified time") equal the time
|
||||
specified with TM. The atime ("access time") is set to the current
|
||||
time. */
|
||||
@@ -703,7 +718,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;
|
||||
@@ -802,7 +817,7 @@ fopen_excl (const char *fname, int binary)
|
||||
return fopen (fname, binary ? "wb" : "w");
|
||||
#endif /* not O_EXCL */
|
||||
}
|
||||
|
||||
|
||||
/* Create DIRECTORY. If some of the pathname components of DIRECTORY
|
||||
are missing, create them first. In case any mkdir() call fails,
|
||||
return its error status. Returns 0 on successful completion.
|
||||
@@ -868,7 +883,7 @@ file_merge (const char *base, const char *file)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Like fnmatch, but performs a case-insensitive match. */
|
||||
|
||||
int
|
||||
@@ -900,15 +915,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 +933,7 @@ acceptable (const char *s)
|
||||
}
|
||||
else if (opt.rejects)
|
||||
return !in_acclist ((const char *const *)opt.rejects, s, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -957,16 +972,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 +1033,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 +1090,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 +1104,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
|
||||
@@ -1129,65 +1124,15 @@ has_html_suffix_p (const char *fname)
|
||||
|
||||
if ((suf = suffix (fname)) == NULL)
|
||||
return false;
|
||||
if (!strcasecmp (suf, "html"))
|
||||
if (!c_strcasecmp (suf, "html"))
|
||||
return true;
|
||||
if (!strcasecmp (suf, "htm"))
|
||||
if (!c_strcasecmp (suf, "htm"))
|
||||
return true;
|
||||
if (suf[0] && !strcasecmp (suf + 1, "html"))
|
||||
if (suf[0] && !c_strcasecmp (suf + 1, "html"))
|
||||
return true;
|
||||
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*
|
||||
@@ -1329,7 +1274,7 @@ wget_read_file_free (struct file_memory *fm)
|
||||
}
|
||||
xfree (fm);
|
||||
}
|
||||
|
||||
|
||||
/* Free the pointers in a NULL-terminated vector of pointers, then
|
||||
free the pointer itself. */
|
||||
void
|
||||
@@ -1398,7 +1343,7 @@ vec_append (char **vec, const char *str)
|
||||
vec[cnt] = NULL;
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
/* Sometimes it's useful to create "sets" of strings, i.e. special
|
||||
hash tables where you want to store strings as keys and merely
|
||||
query for their existence. Here is a set of utility routines that
|
||||
@@ -1463,7 +1408,7 @@ free_keys_and_values (struct hash_table *ht)
|
||||
xfree (iter.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get digit grouping data for thousand separors by calling
|
||||
localeconv(). The data includes separator string and grouping info
|
||||
and is cached after the first call to the function.
|
||||
@@ -1590,7 +1535,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 +1568,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;
|
||||
@@ -1854,7 +1799,7 @@ convert_to_bits (wgint num)
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Determine the width of the terminal we're running on. If that's
|
||||
not possible, return 0. */
|
||||
|
||||
@@ -1867,7 +1812,7 @@ determine_screen_width (void)
|
||||
int fd;
|
||||
struct winsize wsz;
|
||||
|
||||
if (opt.lfilename != NULL)
|
||||
if (opt.lfilename != NULL && opt.show_progress != 1)
|
||||
return 0;
|
||||
|
||||
fd = fileno (stderr);
|
||||
@@ -1884,7 +1829,7 @@ determine_screen_width (void)
|
||||
return 0;
|
||||
#endif /* neither TIOCGWINSZ nor WINDOWS */
|
||||
}
|
||||
|
||||
|
||||
/* Whether the rnd system (either rand or [dl]rand48) has been
|
||||
seeded. */
|
||||
static int rnd_seeded;
|
||||
@@ -1904,7 +1849,14 @@ static int rnd_seeded;
|
||||
int
|
||||
random_number (int max)
|
||||
{
|
||||
#ifdef HAVE_DRAND48
|
||||
#ifdef HAVE_RANDOM
|
||||
if (!rnd_seeded)
|
||||
{
|
||||
srandom ((long) time (NULL) ^ (long) getpid ());
|
||||
rnd_seeded = 1;
|
||||
}
|
||||
return random () % max;
|
||||
#elif defined HAVE_DRAND48
|
||||
if (!rnd_seeded)
|
||||
{
|
||||
srand48 ((long) time (NULL) ^ (long) getpid ());
|
||||
@@ -1939,7 +1891,9 @@ random_number (int max)
|
||||
double
|
||||
random_float (void)
|
||||
{
|
||||
#ifdef HAVE_DRAND48
|
||||
#ifdef HAVE_RANDOM
|
||||
return ((double) random_number (RAND_MAX)) / RAND_MAX;
|
||||
#elif defined HAVE_DRAND48
|
||||
if (!rnd_seeded)
|
||||
{
|
||||
srand48 ((long) time (NULL) ^ (long) getpid ());
|
||||
@@ -1953,7 +1907,7 @@ random_float (void)
|
||||
+ random_number (10000) / (10000.0 * 10000.0 * 10000.0 * 10000.0));
|
||||
#endif /* not HAVE_DRAND48 */
|
||||
}
|
||||
|
||||
|
||||
/* Implementation of run_with_timeout, a generic timeout-forcing
|
||||
routine for systems with Unix-like signal handling. */
|
||||
|
||||
@@ -1963,8 +1917,8 @@ random_float (void)
|
||||
|
||||
static sigjmp_buf run_with_timeout_env;
|
||||
|
||||
static void
|
||||
abort_run_with_timeout (int sig)
|
||||
static void _Noreturn
|
||||
abort_run_with_timeout (int sig _GL_UNUSED)
|
||||
{
|
||||
assert (sig == SIGALRM);
|
||||
siglongjmp (run_with_timeout_env, -1);
|
||||
@@ -1974,8 +1928,8 @@ abort_run_with_timeout (int sig)
|
||||
|
||||
static jmp_buf run_with_timeout_env;
|
||||
|
||||
static void
|
||||
abort_run_with_timeout (int sig)
|
||||
static void _Noreturn
|
||||
abort_run_with_timeout (int sig _GL_UNUSED)
|
||||
{
|
||||
assert (sig == SIGALRM);
|
||||
/* We don't have siglongjmp to preserve the set of blocked signals;
|
||||
@@ -2112,7 +2066,7 @@ run_with_timeout (double timeout, void (*fun) (void *), void *arg)
|
||||
}
|
||||
#endif /* not WINDOWS */
|
||||
#endif /* not USE_SIGNAL_TIMEOUT */
|
||||
|
||||
|
||||
#ifndef WINDOWS
|
||||
|
||||
/* Sleep the specified amount of seconds. On machines without
|
||||
@@ -2172,8 +2126,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 +2189,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,12 +2307,13 @@ 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"),
|
||||
quote (str), errbuf);
|
||||
xfree (errbuf);
|
||||
xfree (regex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2371,10 +2326,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 +2355,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"),
|
||||
@@ -2412,7 +2367,7 @@ match_posix_regex (const void *regex, const char *str)
|
||||
|
||||
#undef IS_ASCII
|
||||
#undef NEXT_CHAR
|
||||
|
||||
|
||||
/* Simple merge sort for use by stable_sort. Implementation courtesy
|
||||
Zeljko Vrba with additional debugging by Nenad Barbutov. */
|
||||
|
||||
@@ -2458,7 +2413,7 @@ stable_sort (void *base, size_t nmemb, size_t size,
|
||||
mergesort_internal (base, temp, size, 0, nmemb - 1, cmpfun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print a decimal number. If it is equal to or larger than ten, the
|
||||
number is rounded. Otherwise it is printed with one significant
|
||||
digit without trailing zeros and with no more than three fractional
|
||||
@@ -2494,21 +2449,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 +2531,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 +2554,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 +2568,3 @@ test_dir_matches_p()
|
||||
}
|
||||
|
||||
#endif /* TESTING */
|
||||
|
||||
|
||||
20
src/utils.h
20
src/utils.h
@@ -47,12 +47,7 @@ as that of the covered work. */
|
||||
|
||||
#define alloca_array(type, size) ((type *) alloca ((size) * sizeof (type)))
|
||||
|
||||
#define xfree free
|
||||
/* Free P if it is non-NULL. C requires free() to behaves this way by
|
||||
default, but Wget's code is historically careful not to pass NULL
|
||||
to free. This allows us to assert p!=NULL in xfree to check
|
||||
additional errors. (But we currently don't do that!) */
|
||||
#define xfree_null(p) if (!(p)) ; else xfree (p)
|
||||
#define xfree(p) do { free ((void *) (p)); p = NULL; } while (0)
|
||||
|
||||
struct hash_table;
|
||||
|
||||
@@ -98,7 +93,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 +116,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 +134,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 +149,12 @@ 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);
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
size_t strlcpy (char *dst, const char *src, size_t size);
|
||||
#endif
|
||||
|
||||
extern unsigned char char_prop[];
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
||||
36
src/version.h
Normal file
36
src/version.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* Extern declarations for printing version information
|
||||
Copyright (C) 2013 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. */
|
||||
|
||||
/* Extern declarations for strings in version.c */
|
||||
extern const char *version_string;
|
||||
extern const char *compilation_string;
|
||||
extern const char *link_string;
|
||||
|
||||
/* Extern declaration for string in build_info.c */
|
||||
extern const char *compiled_features[];
|
||||
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;
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
465
src/warc.c
465
src/warc.c
@@ -27,16 +27,19 @@ Corresponding Source for a non-source form of such a combination
|
||||
shall include the source code for the parts of OpenSSL used as well
|
||||
as that of the covered work. */
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "wget.h"
|
||||
#include "hash.h"
|
||||
#include "utils.h"
|
||||
#include "version.h"
|
||||
#include "dirname.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <tmpdir.h>
|
||||
#include <sha1.h>
|
||||
@@ -45,20 +48,28 @@ as that of the covered work. */
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUUID
|
||||
#include <uuid/uuid.h>
|
||||
#endif
|
||||
|
||||
#ifndef WINDOWS
|
||||
#include <libgen.h>
|
||||
#elif HAVE_UUID_CREATE
|
||||
#include <uuid.h>
|
||||
#endif
|
||||
|
||||
#include "warc.h"
|
||||
#include "exits.h"
|
||||
|
||||
extern char *version_string;
|
||||
#ifdef WINDOWS
|
||||
/* we need this on Windows to have O_TEMPORARY defined */
|
||||
# include <fcntl.h>
|
||||
# include <rpc.h>
|
||||
#endif
|
||||
|
||||
/* Set by main in main.c */
|
||||
extern char *program_argstring;
|
||||
#ifndef O_TEMPORARY
|
||||
#define O_TEMPORARY 0
|
||||
#endif
|
||||
|
||||
#include "warc.h"
|
||||
#include "exits.h"
|
||||
|
||||
|
||||
/* The log file (a temporary file that contains a copy
|
||||
@@ -102,7 +113,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);
|
||||
|
||||
@@ -154,10 +165,12 @@ warc_write_buffer (const char *buffer, size_t size)
|
||||
static bool
|
||||
warc_write_string (const char *str)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
if (!warc_write_ok)
|
||||
return false;
|
||||
|
||||
size_t n = strlen (str);
|
||||
n = strlen (str);
|
||||
if (n != warc_write_buffer (str, n))
|
||||
warc_write_ok = false;
|
||||
|
||||
@@ -165,7 +178,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 +213,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 +258,13 @@ 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)];
|
||||
char buffer[BUFSIZ];
|
||||
size_t s;
|
||||
|
||||
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");
|
||||
@@ -262,8 +273,6 @@ warc_write_block_from_file (FILE *data_in)
|
||||
warc_write_ok = false;
|
||||
|
||||
/* Copy the data in the file to the WARC record. */
|
||||
char buffer[BUFSIZ];
|
||||
size_t s;
|
||||
while (warc_write_ok && (s = fread (buffer, 1, BUFSIZ, data_in)) > 0)
|
||||
{
|
||||
if (warc_write_buffer (buffer, s) < s)
|
||||
@@ -288,6 +297,11 @@ warc_write_end_record (void)
|
||||
/* We start a new gzip stream for each record. */
|
||||
if (warc_write_ok && warc_current_gzfile)
|
||||
{
|
||||
char extra_header[EXTRA_GZIP_HEADER_SIZE];
|
||||
char static_header[GZIP_STATIC_HEADER_SIZE];
|
||||
off_t current_offset, uncompressed_size, compressed_size;
|
||||
size_t result;
|
||||
|
||||
if (gzclose (warc_current_gzfile) != Z_OK)
|
||||
{
|
||||
warc_write_ok = false;
|
||||
@@ -313,17 +327,16 @@ warc_write_end_record (void)
|
||||
*/
|
||||
|
||||
/* Calculate the uncompressed and compressed sizes. */
|
||||
off_t current_offset = ftello (warc_current_file);
|
||||
off_t uncompressed_size = current_offset - warc_current_gzfile_offset;
|
||||
off_t compressed_size = warc_current_gzfile_uncompressed_size;
|
||||
current_offset = ftello (warc_current_file);
|
||||
uncompressed_size = current_offset - warc_current_gzfile_offset;
|
||||
compressed_size = warc_current_gzfile_uncompressed_size;
|
||||
|
||||
/* Go back to the static GZIP header. */
|
||||
fseeko (warc_current_file, warc_current_gzfile_offset
|
||||
+ EXTRA_GZIP_HEADER_SIZE, SEEK_SET);
|
||||
|
||||
/* Read the header. */
|
||||
char static_header[GZIP_STATIC_HEADER_SIZE];
|
||||
size_t result = fread (static_header, 1, GZIP_STATIC_HEADER_SIZE,
|
||||
result = fread (static_header, 1, GZIP_STATIC_HEADER_SIZE,
|
||||
warc_current_file);
|
||||
if (result != GZIP_STATIC_HEADER_SIZE)
|
||||
{
|
||||
@@ -340,23 +353,25 @@ warc_write_end_record (void)
|
||||
fwrite (static_header, 1, GZIP_STATIC_HEADER_SIZE, warc_current_file);
|
||||
|
||||
/* Prepare the extra GZIP header. */
|
||||
char extra_header[EXTRA_GZIP_HEADER_SIZE];
|
||||
/* XLEN, the length of the extra header fields. */
|
||||
extra_header[0] = ((EXTRA_GZIP_HEADER_SIZE - 2) & 255);
|
||||
extra_header[1] = ((EXTRA_GZIP_HEADER_SIZE - 2) >> 8) & 255;
|
||||
/* 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,13 +394,10 @@ warc_write_end_record (void)
|
||||
static bool
|
||||
warc_write_date_header (const char *timestamp)
|
||||
{
|
||||
if (timestamp == NULL)
|
||||
{
|
||||
char current_timestamp[21];
|
||||
warc_timestamp (current_timestamp);
|
||||
timestamp = current_timestamp;
|
||||
}
|
||||
return warc_write_header ("WARC-Date", timestamp);
|
||||
char current_timestamp[21];
|
||||
|
||||
return warc_write_header ("WARC-Date", timestamp ? timestamp :
|
||||
warc_timestamp (current_timestamp, sizeof(current_timestamp)));
|
||||
}
|
||||
|
||||
/* Writes the WARC-IP-Address header for the given IP to
|
||||
@@ -461,7 +473,7 @@ warc_sha1_stream_with_payload (FILE *stream, void *res_block, void *res_payload,
|
||||
or EWOULDBLOCK. */
|
||||
if (ferror (stream))
|
||||
{
|
||||
free (buffer);
|
||||
xfree (buffer);
|
||||
return 1;
|
||||
}
|
||||
goto process_partial_block;
|
||||
@@ -521,7 +533,7 @@ warc_sha1_stream_with_payload (FILE *stream, void *res_block, void *res_payload,
|
||||
sha1_finish_ctx (&ctx_block, res_block);
|
||||
if (payload_offset >= 0)
|
||||
sha1_finish_ctx (&ctx_payload, res_payload);
|
||||
free (buffer);
|
||||
xfree (buffer);
|
||||
return 0;
|
||||
|
||||
#undef BLOCKSIZE
|
||||
@@ -532,7 +544,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);
|
||||
@@ -563,13 +575,13 @@ warc_write_digest_headers (FILE *file, long payload_offset)
|
||||
|
||||
digest = warc_base32_sha1_digest (sha1_res_block);
|
||||
warc_write_header ("WARC-Block-Digest", digest);
|
||||
free (digest);
|
||||
xfree (digest);
|
||||
|
||||
if (payload_offset >= 0)
|
||||
{
|
||||
digest = warc_base32_sha1_digest (sha1_res_payload);
|
||||
warc_write_header ("WARC-Payload-Digest", digest);
|
||||
free (digest);
|
||||
xfree (digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,32 +592,102 @@ warc_write_digest_headers (FILE *file, long payload_offset)
|
||||
The UTC time is formatted following ISO 8601, as required
|
||||
for use in the WARC-Date header.
|
||||
The timestamp will be 21 characters long. */
|
||||
void
|
||||
warc_timestamp (char *timestamp)
|
||||
char *
|
||||
warc_timestamp (char *timestamp, size_t timestamp_size)
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm * timeinfo;
|
||||
time ( &rawtime );
|
||||
timeinfo = gmtime (&rawtime);
|
||||
strftime (timestamp, 21, "%Y-%m-%dT%H:%M:%SZ", timeinfo);
|
||||
time_t rawtime = time (NULL);
|
||||
struct tm * timeinfo = gmtime (&rawtime);
|
||||
|
||||
if (strftime (timestamp, timestamp_size, "%Y-%m-%dT%H:%M:%SZ", timeinfo) == 0 && timestamp_size > 0)
|
||||
*timestamp = 0;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBUUID
|
||||
/* Fills urn_str with a UUID in the format required
|
||||
for the WARC-Record-Id header.
|
||||
The string will be 47 characters long. */
|
||||
#if HAVE_LIBUUID
|
||||
void
|
||||
warc_uuid_str (char *urn_str)
|
||||
{
|
||||
char uuid_str[37];
|
||||
|
||||
uuid_t record_id;
|
||||
|
||||
uuid_generate (record_id);
|
||||
uuid_unparse (record_id, uuid_str);
|
||||
|
||||
sprintf (urn_str, "<urn:uuid:%s>", uuid_str);
|
||||
}
|
||||
#elif HAVE_UUID_CREATE
|
||||
void
|
||||
warc_uuid_str (char *urn_str)
|
||||
{
|
||||
char *uuid_str;
|
||||
uuid_t record_id;
|
||||
|
||||
uuid_create (&record_id, NULL);
|
||||
uuid_to_string (&record_id, &uuid_str, NULL);
|
||||
|
||||
sprintf (urn_str, "<urn:uuid:%s>", uuid_str);
|
||||
xfree (uuid_str);
|
||||
}
|
||||
#else
|
||||
# ifdef WINDOWS
|
||||
|
||||
typedef RPC_STATUS (RPC_ENTRY * UuidCreate_proc) (UUID *);
|
||||
typedef RPC_STATUS (RPC_ENTRY * UuidToString_proc) (UUID *, unsigned char **);
|
||||
typedef RPC_STATUS (RPC_ENTRY * RpcStringFree_proc) (unsigned char **);
|
||||
|
||||
static int
|
||||
windows_uuid_str (char *urn_str)
|
||||
{
|
||||
static UuidCreate_proc pfn_UuidCreate = NULL;
|
||||
static UuidToString_proc pfn_UuidToString = NULL;
|
||||
static RpcStringFree_proc pfn_RpcStringFree = NULL;
|
||||
static int rpc_uuid_avail = -1;
|
||||
|
||||
/* Rpcrt4.dll is not available on older versions of Windows, so we
|
||||
need to test its availability at run time. */
|
||||
if (rpc_uuid_avail == -1)
|
||||
{
|
||||
HMODULE hm_rpcrt4 = LoadLibrary ("Rpcrt4.dll");
|
||||
|
||||
if (hm_rpcrt4)
|
||||
{
|
||||
pfn_UuidCreate =
|
||||
(UuidCreate_proc) GetProcAddress (hm_rpcrt4, "UuidCreate");
|
||||
pfn_UuidToString =
|
||||
(UuidToString_proc) GetProcAddress (hm_rpcrt4, "UuidToStringA");
|
||||
pfn_RpcStringFree =
|
||||
(RpcStringFree_proc) GetProcAddress (hm_rpcrt4, "RpcStringFreeA");
|
||||
if (pfn_UuidCreate && pfn_UuidToString && pfn_RpcStringFree)
|
||||
rpc_uuid_avail = 1;
|
||||
else
|
||||
rpc_uuid_avail = 0;
|
||||
}
|
||||
else
|
||||
rpc_uuid_avail = 0;
|
||||
}
|
||||
|
||||
if (rpc_uuid_avail)
|
||||
{
|
||||
BYTE *uuid_str;
|
||||
UUID uuid;
|
||||
|
||||
if (pfn_UuidCreate (&uuid) == RPC_S_OK)
|
||||
{
|
||||
if (pfn_UuidToString (&uuid, &uuid_str) == RPC_S_OK)
|
||||
{
|
||||
sprintf (urn_str, "<urn:uuid:%s>", uuid_str);
|
||||
pfn_RpcStringFree (&uuid_str);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* Fills urn_str with a UUID based on random numbers in the format
|
||||
required for the WARC-Record-Id header.
|
||||
(See RFC 4122, UUID version 4.)
|
||||
@@ -617,19 +699,27 @@ warc_uuid_str (char *urn_str)
|
||||
void
|
||||
warc_uuid_str (char *urn_str)
|
||||
{
|
||||
// RFC 4122, a version 4 UUID with only random numbers
|
||||
/* RFC 4122, a version 4 UUID with only random numbers */
|
||||
|
||||
unsigned char uuid_data[16];
|
||||
int i;
|
||||
|
||||
#ifdef WINDOWS
|
||||
/* If the native method fails (expected on older Windows versions),
|
||||
use the fallback below. */
|
||||
if (windows_uuid_str (urn_str))
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
uuid_data[i] = random_number (255);
|
||||
|
||||
// Set the four most significant bits (bits 12 through 15) of the
|
||||
// time_hi_and_version field to the 4-bit version number
|
||||
/* Set the four most significant bits (bits 12 through 15) of the
|
||||
* time_hi_and_version field to the 4-bit version number */
|
||||
uuid_data[6] = (uuid_data[6] & 0x0F) | 0x40;
|
||||
|
||||
// Set the two most significant bits (bits 6 and 7) of the
|
||||
// clock_seq_hi_and_reserved to zero and one, respectively.
|
||||
/* Set the two most significant bits (bits 6 and 7) of the
|
||||
* clock_seq_hi_and_reserved to zero and one, respectively. */
|
||||
uuid_data[8] = (uuid_data[8] & 0xBF) | 0x80;
|
||||
|
||||
sprintf (urn_str,
|
||||
@@ -646,18 +736,19 @@ warc_uuid_str (char *urn_str)
|
||||
static bool
|
||||
warc_write_warcinfo_record (char *filename)
|
||||
{
|
||||
FILE *warc_tmp;
|
||||
char timestamp[22];
|
||||
char *filename_basename;
|
||||
|
||||
/* Write warc-info record as the first record of the file. */
|
||||
/* We add the record id of this info record to the other records in the
|
||||
file. */
|
||||
warc_current_warcinfo_uuid_str = (char *) malloc (48);
|
||||
warc_uuid_str (warc_current_warcinfo_uuid_str);
|
||||
|
||||
char timestamp[22];
|
||||
warc_timestamp (timestamp);
|
||||
warc_timestamp (timestamp, sizeof(timestamp));
|
||||
|
||||
char *filename_copy, *filename_basename;
|
||||
filename_copy = strdup (filename);
|
||||
filename_basename = strdup (basename (filename_copy));
|
||||
filename_basename = base_name (filename);
|
||||
|
||||
warc_write_start_record ();
|
||||
warc_write_header ("WARC-Type", "warcinfo");
|
||||
@@ -666,12 +757,12 @@ warc_write_warcinfo_record (char *filename)
|
||||
warc_write_header ("WARC-Record-ID", warc_current_warcinfo_uuid_str);
|
||||
warc_write_header ("WARC-Filename", filename_basename);
|
||||
|
||||
xfree (filename_basename);
|
||||
|
||||
/* Create content. */
|
||||
FILE *warc_tmp = warc_tempfile ();
|
||||
warc_tmp = warc_tempfile ();
|
||||
if (warc_tmp == NULL)
|
||||
{
|
||||
free (filename_copy);
|
||||
free (filename_basename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -697,8 +788,6 @@ warc_write_warcinfo_record (char *filename)
|
||||
if (! warc_write_ok)
|
||||
logprintf (LOG_NOTQUIET, _("Error writing warcinfo record to WARC file.\n"));
|
||||
|
||||
free (filename_copy);
|
||||
free (filename_basename);
|
||||
fclose (warc_tmp);
|
||||
return warc_write_ok;
|
||||
}
|
||||
@@ -717,29 +806,37 @@ warc_write_warcinfo_record (char *filename)
|
||||
static bool
|
||||
warc_start_new_file (bool meta)
|
||||
{
|
||||
#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");
|
||||
#else
|
||||
const char *extension = "warc";
|
||||
#endif
|
||||
|
||||
int base_filename_length;
|
||||
char *new_filename;
|
||||
|
||||
if (opt.warc_filename == NULL)
|
||||
return false;
|
||||
|
||||
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);
|
||||
|
||||
xfree (warc_current_warcinfo_uuid_str);
|
||||
xfree (warc_current_filename);
|
||||
|
||||
warc_current_file_number++;
|
||||
|
||||
int base_filename_length = strlen (opt.warc_filename);
|
||||
base_filename_length = strlen (opt.warc_filename);
|
||||
/* filename format: base + "-" + 5 digit serial number + ".warc.gz" */
|
||||
char *new_filename = malloc (base_filename_length + 1 + 5 + 8 + 1);
|
||||
new_filename = malloc (base_filename_length + 1 + 5 + 8 + 1);
|
||||
warc_current_filename = new_filename;
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
const char *extension = (opt.warc_compression_enabled ? "warc.gz" : "warc");
|
||||
#else
|
||||
const char *extension = "warc";
|
||||
#endif
|
||||
|
||||
/* If max size is enabled, we add a serial number to the file names. */
|
||||
if (meta)
|
||||
sprintf (new_filename, "%s-meta.%s", opt.warc_filename, extension);
|
||||
@@ -811,12 +908,13 @@ static bool
|
||||
warc_parse_cdx_header (char *lineptr, int *field_num_original_url,
|
||||
int *field_num_checksum, int *field_num_record_id)
|
||||
{
|
||||
char *token;
|
||||
char *save_ptr;
|
||||
|
||||
*field_num_original_url = -1;
|
||||
*field_num_checksum = -1;
|
||||
*field_num_record_id = -1;
|
||||
|
||||
char *token;
|
||||
char *save_ptr;
|
||||
token = strtok_r (lineptr, CDX_FIELDSEP, &save_ptr);
|
||||
|
||||
if (token != NULL && strcmp (token, "CDX") == 0)
|
||||
@@ -857,13 +955,12 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
|
||||
char *original_url = NULL;
|
||||
char *checksum = NULL;
|
||||
char *record_id = NULL;
|
||||
|
||||
char *token;
|
||||
char *save_ptr;
|
||||
token = strtok_r (lineptr, CDX_FIELDSEP, &save_ptr);
|
||||
int field_num = 0;
|
||||
|
||||
/* Read this line to get the fields we need. */
|
||||
int field_num = 0;
|
||||
token = strtok_r (lineptr, CDX_FIELDSEP, &save_ptr);
|
||||
while (token != NULL)
|
||||
{
|
||||
char **val;
|
||||
@@ -892,7 +989,7 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
|
||||
char * checksum_v;
|
||||
base32_decode_alloc (checksum, strlen (checksum), &checksum_v,
|
||||
&checksum_l);
|
||||
free (checksum);
|
||||
xfree (checksum);
|
||||
|
||||
if (checksum_v != NULL && checksum_l == SHA1_DIGEST_SIZE)
|
||||
{
|
||||
@@ -903,21 +1000,20 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
|
||||
rec->uuid = record_id;
|
||||
memcpy (rec->digest, checksum_v, SHA1_DIGEST_SIZE);
|
||||
hash_table_put (warc_cdx_dedup_table, rec->digest, rec);
|
||||
free (checksum_v);
|
||||
xfree (checksum_v);
|
||||
}
|
||||
else
|
||||
{
|
||||
free (original_url);
|
||||
if (checksum_v != NULL)
|
||||
free (checksum_v);
|
||||
free (record_id);
|
||||
xfree (original_url);
|
||||
xfree (checksum_v);
|
||||
xfree (record_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xfree_null(checksum);
|
||||
xfree_null(original_url);
|
||||
xfree_null(record_id);
|
||||
xfree(checksum);
|
||||
xfree(original_url);
|
||||
xfree(record_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,17 +1022,17 @@ warc_process_cdx_line (char *lineptr, int field_num_original_url,
|
||||
static bool
|
||||
warc_load_cdx_dedup_file (void)
|
||||
{
|
||||
FILE *f = fopen (opt.warc_cdx_dedup_filename, "r");
|
||||
if (f == NULL)
|
||||
return false;
|
||||
|
||||
FILE *f;
|
||||
char *lineptr = NULL;
|
||||
size_t n = 0;
|
||||
ssize_t line_length;
|
||||
int field_num_original_url = -1;
|
||||
int field_num_checksum = -1;
|
||||
int field_num_record_id = -1;
|
||||
|
||||
char *lineptr = NULL;
|
||||
size_t n = 0;
|
||||
ssize_t line_length;
|
||||
f = fopen (opt.warc_cdx_dedup_filename, "r");
|
||||
if (f == NULL)
|
||||
return false;
|
||||
|
||||
/* The first line should contain the CDX header.
|
||||
Format: " CDX x x x x x"
|
||||
@@ -965,6 +1061,8 @@ _("CDX file does not list record ids. (Missing column 'u'.)\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
int nrecords;
|
||||
|
||||
/* Initialize the table. */
|
||||
warc_cdx_dedup_table = hash_table_new (1000, warc_hash_sha1_digest,
|
||||
warc_cmp_sha1_digest);
|
||||
@@ -982,14 +1080,14 @@ _("CDX file does not list record ids. (Missing column 'u'.)\n"));
|
||||
while (line_length != -1);
|
||||
|
||||
/* Print results. */
|
||||
int nrecords = hash_table_count (warc_cdx_dedup_table);
|
||||
nrecords = hash_table_count (warc_cdx_dedup_table);
|
||||
logprintf (LOG_VERBOSE, ngettext ("Loaded %d record from CDX.\n\n",
|
||||
"Loaded %d records from CDX.\n\n",
|
||||
nrecords),
|
||||
nrecords);
|
||||
}
|
||||
|
||||
free (lineptr);
|
||||
xfree (lineptr);
|
||||
fclose (f);
|
||||
|
||||
return true;
|
||||
@@ -1002,15 +1100,14 @@ _("CDX file does not list record ids. (Missing column 'u'.)\n"));
|
||||
static struct warc_cdx_record *
|
||||
warc_find_duplicate_cdx_record (char *url, char *sha1_digest_payload)
|
||||
{
|
||||
struct warc_cdx_record *rec_existing;
|
||||
|
||||
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);
|
||||
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 +1129,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 +1138,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 +1148,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 +1157,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 +1166,7 @@ warc_init (void)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET,
|
||||
_("Could not open CDX file for output.\n"));
|
||||
exit(1);
|
||||
exit (WGET_EXIT_GENERIC_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1079,32 +1176,34 @@ warc_init (void)
|
||||
static void
|
||||
warc_write_metadata (void)
|
||||
{
|
||||
char manifest_uuid[48];
|
||||
FILE *warc_tmp_fp;
|
||||
|
||||
/* If there are multiple WARC files, the metadata should be written to a separate file. */
|
||||
if (opt.warc_maxsize > 0)
|
||||
warc_start_new_file (true);
|
||||
|
||||
char manifest_uuid [48];
|
||||
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);
|
||||
/* warc_write_resource_record has closed warc_manifest_fp. */
|
||||
|
||||
FILE * warc_tmp_fp = warc_tempfile ();
|
||||
warc_tmp_fp = warc_tempfile ();
|
||||
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. */
|
||||
|
||||
@@ -1129,7 +1228,7 @@ warc_close (void)
|
||||
if (warc_current_file != NULL)
|
||||
{
|
||||
warc_write_metadata ();
|
||||
free (warc_current_warcinfo_uuid_str);
|
||||
xfree (warc_current_warcinfo_uuid_str);
|
||||
fclose (warc_current_file);
|
||||
}
|
||||
if (warc_current_cdx_file != NULL)
|
||||
@@ -1148,17 +1247,40 @@ FILE *
|
||||
warc_tempfile (void)
|
||||
{
|
||||
char filename[100];
|
||||
int fd;
|
||||
|
||||
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 */
|
||||
fd = mkostemp (filename, O_TEMPORARY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
#if !O_TEMPORARY
|
||||
if (unlink (filename) < 0)
|
||||
return NULL;
|
||||
{
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return fdopen (fd, "wb+");
|
||||
#endif /* def __VMS [else] */
|
||||
}
|
||||
|
||||
|
||||
@@ -1207,11 +1329,14 @@ 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. */
|
||||
char timestamp_str_cdx [15];
|
||||
char timestamp_str_cdx[15];
|
||||
char offset_string[MAX_INT_TO_STRING_LEN(off_t)];
|
||||
const char *checksum;
|
||||
|
||||
memcpy (timestamp_str_cdx , timestamp_str , 4); /* "YYYY" "-" */
|
||||
memcpy (timestamp_str_cdx + 4, timestamp_str + 5, 2); /* "mm" "-" */
|
||||
memcpy (timestamp_str_cdx + 6, timestamp_str + 8, 2); /* "dd" "T" */
|
||||
@@ -1221,7 +1346,6 @@ warc_write_cdx_record (const char *url, const char *timestamp_str,
|
||||
timestamp_str_cdx[14] = '\0';
|
||||
|
||||
/* Rewrite the checksum. */
|
||||
const char *checksum;
|
||||
if (payload_digest != NULL)
|
||||
checksum = payload_digest + 5; /* Skip the "sha1:" */
|
||||
else
|
||||
@@ -1232,10 +1356,13 @@ warc_write_cdx_record (const char *url, const char *timestamp_str,
|
||||
if (redirect_location == NULL || strlen(redirect_location) == 0)
|
||||
redirect_location = "-";
|
||||
|
||||
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;
|
||||
@@ -1260,10 +1387,11 @@ warc_write_revisit_record (char *url, char *timestamp_str,
|
||||
char *refers_to, ip_address *ip, FILE *body)
|
||||
{
|
||||
char revisit_uuid [48];
|
||||
warc_uuid_str (revisit_uuid);
|
||||
|
||||
char *block_digest = NULL;
|
||||
char sha1_res_block[SHA1_DIGEST_SIZE];
|
||||
|
||||
warc_uuid_str (revisit_uuid);
|
||||
|
||||
sha1_stream (body, sha1_res_block);
|
||||
block_digest = warc_base32_sha1_digest (sha1_res_block);
|
||||
|
||||
@@ -1285,7 +1413,7 @@ warc_write_revisit_record (char *url, char *timestamp_str,
|
||||
warc_write_end_record ();
|
||||
|
||||
fclose (body);
|
||||
free (block_digest);
|
||||
xfree (block_digest);
|
||||
|
||||
return warc_write_ok;
|
||||
}
|
||||
@@ -1313,6 +1441,8 @@ warc_write_response_record (char *url, char *timestamp_str,
|
||||
char *payload_digest = NULL;
|
||||
char sha1_res_block[SHA1_DIGEST_SIZE];
|
||||
char sha1_res_payload[SHA1_DIGEST_SIZE];
|
||||
char response_uuid [48];
|
||||
off_t offset;
|
||||
|
||||
if (opt.warc_digests_enabled)
|
||||
{
|
||||
@@ -1345,7 +1475,7 @@ warc_write_response_record (char *url, char *timestamp_str,
|
||||
result = warc_write_revisit_record (url, timestamp_str,
|
||||
concurrent_to_uuid, payload_digest, rec_existing->uuid,
|
||||
ip, body);
|
||||
free (payload_digest);
|
||||
xfree (payload_digest);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1357,11 +1487,10 @@ warc_write_response_record (char *url, char *timestamp_str,
|
||||
|
||||
/* Not a revisit, just store the record. */
|
||||
|
||||
char response_uuid [48];
|
||||
warc_uuid_str (response_uuid);
|
||||
|
||||
fseeko (warc_current_file, 0L, SEEK_END);
|
||||
off_t offset = ftello (warc_current_file);
|
||||
offset = ftello (warc_current_file);
|
||||
|
||||
warc_write_start_record ();
|
||||
warc_write_header ("WARC-Type", "response");
|
||||
@@ -1387,28 +1516,28 @@ warc_write_response_record (char *url, char *timestamp_str,
|
||||
response_uuid);
|
||||
}
|
||||
|
||||
if (block_digest)
|
||||
free (block_digest);
|
||||
if (payload_digest)
|
||||
free (payload_digest);
|
||||
xfree (block_digest);
|
||||
xfree (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 +1551,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 +1567,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);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
void warc_init (void);
|
||||
void warc_close (void);
|
||||
void warc_timestamp (char *timestamp);
|
||||
void warc_uuid_str (char *id_str);
|
||||
|
||||
char * warc_timestamp (char *timestamp, size_t timestamp_size);
|
||||
|
||||
FILE * warc_tempfile (void);
|
||||
|
||||
bool warc_write_request_record (char *url, char *timestamp_str,
|
||||
@@ -19,5 +20,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 */
|
||||
|
||||
114
src/wget.h
114
src/wget.h
@@ -59,7 +59,7 @@ as that of the covered work. */
|
||||
/* `gettext (FOO)' is long to write, so we use `_(FOO)'. If NLS is
|
||||
unavailable, _(STRING) simply returns STRING. */
|
||||
#include "gettext.h"
|
||||
#define _(string) gettext (string)
|
||||
#define _(STRING) gettext(STRING)
|
||||
|
||||
/* A pseudo function call that serves as a marker for the automated
|
||||
extraction of messages, but does not call gettext(). The run-time
|
||||
@@ -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,25 +248,25 @@ 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 \
|
||||
&& !strncasecmp (beg, string_literal, sizeof (string_literal) - 1))
|
||||
#define BOUNDED_EQUAL_NO_CASE(beg, end, string_literal) \
|
||||
((end) - (beg) == sizeof (string_literal) - 1 \
|
||||
&& !c_strncasecmp (beg, string_literal, sizeof (string_literal) - 1))
|
||||
|
||||
/* Like ptr=strdup(str), but allocates the space for PTR on the stack.
|
||||
This cannot be an expression because this is not portable:
|
||||
@@ -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,30 @@ 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)
|
||||
|
||||
/* Find the minimum or maximum of two provided values */
|
||||
# define MIN(i, j) ((i) <= (j) ? (i) : (j))
|
||||
# define MAX(i, j) ((i) >= (j) ? (i) : (j))
|
||||
|
||||
|
||||
extern const char *exec_name;
|
||||
|
||||
extern const char *program_name;
|
||||
extern const char *program_argstring;
|
||||
|
||||
/* 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,27 +339,18 @@ 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, GATEWAYTIMEOUT,
|
||||
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,
|
||||
|
||||
UNLINKERR, NEWLOCATION_KEEP_POST, CLOSEFAILED, ATTRMISSING, UNKNOWNATTR,
|
||||
WARC_ERR, WARC_TMP_FOPENERR, WARC_TMP_FWRITEERR
|
||||
} uerr_t;
|
||||
|
||||
@@ -362,7 +358,7 @@ typedef enum
|
||||
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
|
||||
|
||||
65
testenv/Makefile.am
Normal file
65
testenv/Makefile.am
Normal file
@@ -0,0 +1,65 @@
|
||||
# Makefile for `wget' utility
|
||||
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Wget. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Additional permission under GNU GPL version 3 section 7
|
||||
|
||||
# If you modify this program, or any covered work, by linking or
|
||||
# combining it with the OpenSSL project's OpenSSL library (or a
|
||||
# modified version of that library), containing parts covered by the
|
||||
# terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
|
||||
# grants you additional permission to convey the resulting work.
|
||||
# Corresponding Source for a non-source form of such a combination
|
||||
# shall include the source code for the parts of OpenSSL used as well
|
||||
# as that of the covered work.
|
||||
|
||||
|
||||
AUTOMAKE_OPTIONS = parallel-tests
|
||||
AM_TESTS_ENVIRONMENT = export WGETRC=/dev/null; MAKE_CHECK=True; export MAKE_CHECK;\
|
||||
export PYTHONPATH=$$PYTHONPATH:$(srcdir); export VALGRIND_TESTS="@VALGRIND_TESTS@";
|
||||
if HAVE_PYTHON3
|
||||
TESTS = Test-auth-basic-fail.py \
|
||||
Test-auth-basic.py \
|
||||
Test-auth-both.py \
|
||||
Test-auth-digest.py \
|
||||
Test-auth-no-challenge.py \
|
||||
Test-auth-no-challenge-url.py \
|
||||
Test-auth-retcode.py \
|
||||
Test-auth-with-content-disposition.py \
|
||||
Test-c-full.py \
|
||||
Test-Content-disposition-2.py \
|
||||
Test-Content-disposition.py \
|
||||
Test-cookie-401.py \
|
||||
Test-cookie-domain-mismatch.py \
|
||||
Test-cookie-expires.py \
|
||||
Test-cookie.py \
|
||||
Test-Head.py \
|
||||
Test--https.py \
|
||||
Test--https-crl.py \
|
||||
Test-O.py \
|
||||
Test-Post.py \
|
||||
Test-504.py \
|
||||
Test--spider-r.py \
|
||||
Test-redirect-crash.py
|
||||
|
||||
# added test cases expected to fail here and under TESTS
|
||||
XFAIL_TESTS =
|
||||
endif
|
||||
|
||||
EXTRA_DIST = certs conf exc misc server test README $(TESTS) $(XFAIL_TESTS)
|
||||
|
||||
TEST_EXTENSIONS = .py
|
||||
PY_LOG_COMPILER = python3
|
||||
AM_PY_LOG_FLAGS = -O
|
||||
305
testenv/README
Normal file
305
testenv/README
Normal file
@@ -0,0 +1,305 @@
|
||||
This document describes the working of the GNU Wget Test Suite.
|
||||
|
||||
Install Instructions:
|
||||
================================================================================
|
||||
|
||||
This Test Suite exploits the Parallel Test Harness available in GNU Autotools.
|
||||
Since it uses features from a relatively recent verion of Autotools, the minimum
|
||||
required version as been bumped up to 1.11.
|
||||
Run the './configure' command to generate the Makefile and then run 'make check'
|
||||
to execute the Test Suite. Use the '-j n' option with 'make check' to execute
|
||||
n tests simultaneously.
|
||||
|
||||
Structure:
|
||||
================================================================================
|
||||
|
||||
* server: This package contains custom programmatically configurable servers
|
||||
(both HTTP and FTP) for testing Wget. The HTTP server runs an instance of
|
||||
Python's http.server module. The FTP server is to be implemented.
|
||||
|
||||
* test: This package contains the test case classes for HTTP and FTP. The
|
||||
test case classes includes methods for initializing and cleaning up of the
|
||||
test environment.
|
||||
|
||||
* Test-Proto.py: This is a prototype Test Case file. The file defines all
|
||||
the acceptable elements and their uses. Typically, one must copy this file
|
||||
and edit it for writing Test Cases.
|
||||
|
||||
* exc: This package contains custom exception classes used in this test
|
||||
suite.
|
||||
|
||||
* conf: This package contains the configuration classes for servers to be
|
||||
configured with.
|
||||
|
||||
* misc: This package contains several helper modules used in this test
|
||||
suite.
|
||||
- colour_terminal.py: A custom module for printing coloured output to
|
||||
the terminal. Currently it only supports 4 colours in a *nix
|
||||
environment.
|
||||
- wget_file.py: Module which contains WgetFile, which is a file data
|
||||
container object.
|
||||
|
||||
Working:
|
||||
================================================================================
|
||||
|
||||
The Test Files are valid Python scripts and the default mask for them is 755.
|
||||
A singular Test must be invoked in the following manner:
|
||||
$ ./python3 <Name of Test File> OR
|
||||
$ ./<Name of Test File>
|
||||
The script will then initialize the various elements and pass them to an object
|
||||
of the respective Test Class. A directory with the name <Test name>-test will be
|
||||
created and the PWD will be changed to this directory. The server is then
|
||||
spawned with the required configuration elements. A blocking call to Wget is
|
||||
made with the command line arguments specified in the Test Case along with the
|
||||
list of URLs that it must download. The server is killed once Wget returns and
|
||||
the following checks are used to determine the pass/fail status of the test:
|
||||
* Return Code: The Exit code of Wget is matched against the expected Exit
|
||||
Code as mentioned in the Test Case File.
|
||||
* Downloaded Files: Check whether the expected downloaded files exist on
|
||||
disk.
|
||||
* File Content: Test whether the file contents were correctly downloaded by
|
||||
Wget and not corrupted mid-way.
|
||||
* Excess Files: Check to see whether any unexpected files were downloaded
|
||||
by Wget.
|
||||
|
||||
Exit Codes:
|
||||
===============================================================================
|
||||
|
||||
Following is a list of Exit Status Codes for the tests:
|
||||
* 0 Test Successful
|
||||
* 66 Errors/Warnings Reported by Thread Sanitizer (If built with -fsanitize)
|
||||
* 77 Test Skipped
|
||||
* 99 Hard Error
|
||||
* 100 Test Failed
|
||||
|
||||
Tests are skipped when they are either not supported by the platform, or Wget
|
||||
is not compiled with support for that feature. This feature has not yet been
|
||||
implemented.
|
||||
|
||||
Hard Errors occur when there are problems with the Environment code. Hard
|
||||
Error reporting is currently not enabled and all errors are reported as
|
||||
failures.
|
||||
|
||||
All exceptions should ideally be handled gracefully. If you see any unhandled
|
||||
exceptions, please file a bug report at <bug-wget@gnu.org>
|
||||
|
||||
Environment Variables:
|
||||
================================================================================
|
||||
|
||||
* SERVER_WAIT: Set this environment variable with a value for the number of
|
||||
seconds the test should sleep between invoking the server and calling the Wget
|
||||
executable. This is used when one would like to test a different version of
|
||||
the executable or for running the test through external utilities like gdb and
|
||||
valgrind.
|
||||
* NO_CLEANUP: Do not remove the temporary files created by the test.
|
||||
This will prevent the ${testname}-test directory from being deleted
|
||||
* VALGRIND_TESTS: If this variable is set and contains the valgrind command line,
|
||||
the test suite will execute all the tests via this command.
|
||||
If it is set to "1", valgrind memcheck is enabled with hard coded options.
|
||||
This variable is set by ./configure --enable-valgrind-tests.
|
||||
|
||||
|
||||
File Structure:
|
||||
================================================================================
|
||||
|
||||
The test case files are Python scripts. It is believed that Python is a simple
|
||||
yet elegant language and should be easy for everyone to comprehend. This test
|
||||
suite is written with the objective of making it easy to write new tests. The
|
||||
structure has been kept as intuitive as possible and should not require much
|
||||
effort to get accustomed to.
|
||||
|
||||
All Test Files MUST begin with the following Three Lines:
|
||||
#!/usr/bin/python3
|
||||
from sys import exit
|
||||
from WgetTest import {HTTPTest|FTPTest}
|
||||
from misc.wget_file import WgetFile
|
||||
|
||||
It is recommended that a small description of the Test Case is provided next.
|
||||
This would be very helpful to future contributors.
|
||||
Next, is the const variable, TEST_NAME that defines the name of the Test.
|
||||
|
||||
Each File in the Test must be represented as a WgetFile object. The WgetFile
|
||||
Class has the following prototype:
|
||||
WgetFile (str name, str contents, str timestamp, dict rules)
|
||||
None except name is a mandatory paramter, one may pass only those parameters
|
||||
that are required by the File object.
|
||||
|
||||
The timestamp string should be a valid Unix Timestamp as defined in RFC xxxx.
|
||||
The rules object is a dictionary element, with the key as the Rule Name and
|
||||
value as the Rule Data. In most cases, the Rule Data is another dictionary.
|
||||
|
||||
Various variables used consistently across all tests are:
|
||||
* WGET_OPTIONS: The command line string passed to Wget upon invokation. This
|
||||
string may contain URLs, like in the case where in-URL authentication is
|
||||
used. Variable names passed like {{var_name}} will be replaced by the
|
||||
contents of the variable self.var_name before being passed to Wget
|
||||
* WGET_URLS: This is a list of filenames which will be appended as the URLs
|
||||
to Wget during invokation. This is a list of lists, where WGET_URLS[0]
|
||||
represents the list of Filenames called from Server[0], WGET_URLS[1] is a
|
||||
list of files downloaded from Server[2], etc.
|
||||
* Files: This variable defines the files that exist in the Server's
|
||||
filesystem. The Files variable is a list of lists of WgetFile objects.
|
||||
This means that File[0] is a list of WgetFile objects that lie on Server[0],
|
||||
File[1] a list of files on Server[1] and so on.
|
||||
* Existing_Files: This is a list of files that already exist in the
|
||||
directory from which Wget is invoked.
|
||||
* ExpectedReturnCode: The Exit Code expected to be returned by Wget after
|
||||
the test.
|
||||
* ExpectedDownloadedFiles: A list of files that are expected in the local
|
||||
directory after Wget has finished executing. This does not include the files
|
||||
already existing before Wget was launched and must be mentioned again.
|
||||
* Request_List: An unordered list of Requests that each server must receive.
|
||||
This too is a list of lists and follows the same convention as others above.
|
||||
|
||||
Both, the HTTPTest and FTPTest modules have the same prototype:
|
||||
{
|
||||
name,
|
||||
pre_hook,
|
||||
test_options,
|
||||
post_hook,
|
||||
protocols
|
||||
}
|
||||
name should be a string, and is usually passed to the TEST_NAME variable,
|
||||
the three hooks should be Python dict objects and protocols should be a list of
|
||||
protocols, like [HTTP, HTTPS].
|
||||
|
||||
Valid File Rules:
|
||||
================================================================================
|
||||
|
||||
This section lists the currently supported File Rules and their structure.
|
||||
|
||||
* Authentication: Used when a File must require Authorization for access.
|
||||
The value for this key is the following dictionary:
|
||||
|-->Type : Basic|Digest|Both|Both_inline
|
||||
|-->User : <Username>
|
||||
--->Pass : <Password>
|
||||
|
||||
* ExpectHeader : The following Headers MUST exist in every Request for the
|
||||
File. The value for this key is a dictionary object where each header is
|
||||
represented as:
|
||||
|-->Header Name : <Header Data>
|
||||
|
||||
* RejectHeader : This list of Headers must NEVER occur in a request. It
|
||||
uses the same value format as ExpectHeader.
|
||||
|
||||
* SendHeader : This list of Headers will be sent in EVERY response to a
|
||||
request for the respective file. It follows the same value format as
|
||||
ExpectHeader.
|
||||
|
||||
* Response : The HTTP Response Code to send to a request for this File.
|
||||
The value is an Integer that represents a valid HTTP Response Code.
|
||||
|
||||
Pre Test Hooks:
|
||||
================================================================================
|
||||
|
||||
The Pre-Test Hooks are executed just after starting the server and just before
|
||||
spawning an instance of the server. These are usually used for setting up the
|
||||
Test Environment and Server Rules. The currently supported Pre-Test Hooks are:
|
||||
|
||||
* ServerFiles : A list of WgetFile objects that must exist on the Server
|
||||
* LocalFiles : A list of WgetFile objects that exist locally on disk
|
||||
before Wget is executed.
|
||||
|
||||
Since pre_test is a dictionary, one may not assume that the hooks will be
|
||||
executed in the same order as they are defined.
|
||||
|
||||
Test Options:
|
||||
================================================================================
|
||||
|
||||
The test_options dictionary defines the commands to be used when the Test is
|
||||
executed. The currently supported options are:
|
||||
|
||||
* Urls : A list of the filenames that Wget must attempt to
|
||||
download. The complete URL will be created and passed to Wget
|
||||
automatically. (alias URLs)
|
||||
* WgetCommands : A string consisting of the various commandline switches
|
||||
sent to Wget upon invokation. Any data placed between {{ }} in this string
|
||||
will be replaced with the contents of self.<data> before being passed to
|
||||
Wget. This is particularly useful for getting the hostname and port for a
|
||||
file. While all Download URL's are passed to Urls, a notable exception is
|
||||
when in-url authentication is used. In such a case, the URL is specified in
|
||||
the WgetCommands string.
|
||||
|
||||
Post-Test Hooks:
|
||||
================================================================================
|
||||
|
||||
These hooks are executed as soon as the call to Wget returns. The post-test
|
||||
hooks are usually used to run checks on the data, files downloaded, return code,
|
||||
etc. The following hooks are currently supported:
|
||||
|
||||
* ExpectedRetcode : This is an integer value of the ReturnCode with which
|
||||
Wget is expected to exit. (alias ExpectedRetCode)
|
||||
* ExpectedFiles : This is a list of WgetFile objects of the files that
|
||||
must exist locally on disk in the Test directory.
|
||||
* FilesCrawled : This requires a list of the Requests that the server is
|
||||
expected to receive. The order is un-important since it will vary on the
|
||||
parallel-wget branch. This hook is used in tests for Recursive mode to
|
||||
ensure that the website is traversed correctly.
|
||||
|
||||
Writing New Tests:
|
||||
================================================================================
|
||||
|
||||
See Test-Proto.py for an example of how to write Test Case files. The
|
||||
recommended method for writing new Test Case files is to copy Test-Proto.py and
|
||||
modify it to ones needs.
|
||||
|
||||
In case you require any functionality that is not currently defined in List of
|
||||
Rules defined above, you should implement a new class in the conf package. The
|
||||
file name doesn't matter (though it's better to give it an appropriate name).
|
||||
The new rule or hook class should be like this:
|
||||
============================================
|
||||
from conf import rule
|
||||
|
||||
|
||||
@rule()
|
||||
class MyNewRule:
|
||||
def __init__(self, rule_arg):
|
||||
self.rule_arg = rule_arg
|
||||
# your rule initialization code goes here
|
||||
============================================
|
||||
from conf import hook
|
||||
|
||||
|
||||
@hook()
|
||||
class MyNewHook:
|
||||
def __init__(self, hook_arg):
|
||||
self.hook_arg = hook_arg
|
||||
# your hook initialization code goes here
|
||||
|
||||
def __call__(self, test_obj):
|
||||
# your hook code goes here
|
||||
============================================
|
||||
|
||||
Once a new Test File is created, it must be added to the TESTS variable in
|
||||
Makefile.am. This way the Test will be executed on running a 'make check'.
|
||||
If a Test is expected to fail on the current master branch, then the Test should
|
||||
also be added to the XFAIL_TESTS variable. This will allow expected failures to
|
||||
pass through. If a test mentioned in the XFAIL_TESTS variable passes, it gets
|
||||
red-flagged as a XPASS. Currently, tests expected to fail under valgrind are not
|
||||
explicitly marked as XFAIL. Tests failing under valgrind must always be
|
||||
considered a blocking error.
|
||||
|
||||
Remember to always name the Test correctly using the TEST_NAME variable. This
|
||||
is essential since a directory with the Test Name is created and this can
|
||||
cause synchronization problems when the Parallel Test Harness is used.
|
||||
One can use the following command on Unix systems to check for TEST_NAME
|
||||
clashes:
|
||||
$ grep -r -h "TEST_NAME =" | cut -c13- | uniq -c -d
|
||||
|
||||
Work Remaining:
|
||||
================================================================================
|
||||
|
||||
Some amount of work still remains to be done.
|
||||
* Errors in server-side checks need to be handled more explicitly
|
||||
* Support parallel-wget branch
|
||||
* Support to spawn multiple servers is already in place. Need to handle
|
||||
multiple requests to a server simultaneously. Use THreading MixIn.
|
||||
* SSL Tests. Use xyne's HTTPS server implemention
|
||||
* Complete support for FTP Tests
|
||||
* IRI Support. This shouldn't require much effort
|
||||
|
||||
Requirements:
|
||||
================================================================================
|
||||
|
||||
1. Python >= 3.0
|
||||
2. Automake >= 1.11
|
||||
50
testenv/Test--https-crl.py
Executable file
50
testenv/Test--https-crl.py
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from test.base_test import HTTP, HTTPS
|
||||
from misc.wget_file import WgetFile
|
||||
import os
|
||||
|
||||
"""
|
||||
This test ensures that Wget can download files from HTTPS Servers
|
||||
"""
|
||||
TEST_NAME = "HTTPS CRL"
|
||||
############# File Definitions ###############################################
|
||||
File1 = "Would you like some Tea?"
|
||||
File2 = "With lemon or cream?"
|
||||
|
||||
A_File = WgetFile ("File1", File1)
|
||||
B_File = WgetFile ("File2", File2)
|
||||
|
||||
CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
|
||||
CRLFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'server-crl.pem'))
|
||||
WGET_OPTIONS = "--crl-file " + CRLFILE + " --ca-certificate=" + CAFILE
|
||||
WGET_URLS = [["File1", "File2"]]
|
||||
|
||||
Files = [[A_File, B_File]]
|
||||
|
||||
Servers = [HTTPS]
|
||||
|
||||
ExpectedReturnCode = 5
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedRetcode" : ExpectedReturnCode
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test,
|
||||
protocols=Servers
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
55
testenv/Test--https.py
Executable file
55
testenv/Test--https.py
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
from sys import exit
|
||||
from test.http_test import HTTPTest
|
||||
from test.base_test import HTTP, HTTPS
|
||||
from misc.wget_file import WgetFile
|
||||
import os
|
||||
|
||||
"""
|
||||
This test ensures that Wget can download files from HTTPS Servers
|
||||
"""
|
||||
TEST_NAME = "HTTPS Downloads"
|
||||
############# File Definitions ###############################################
|
||||
File1 = "Would you like some Tea?"
|
||||
File2 = "With lemon or cream?"
|
||||
File3 = "Sure you're joking Mr. Feynman"
|
||||
|
||||
A_File = WgetFile ("File1", File1)
|
||||
B_File = WgetFile ("File2", File2)
|
||||
C_File = WgetFile ("File3", File3)
|
||||
|
||||
CAFILE = os.path.abspath(os.path.join(os.getenv('srcdir', '.'), 'certs', 'ca-cert.pem'))
|
||||
WGET_OPTIONS = "--ca-certificate=" + CAFILE
|
||||
WGET_URLS = [["File1", "File2"]]
|
||||
|
||||
Files = [[A_File, B_File]]
|
||||
Existing_Files = [C_File]
|
||||
|
||||
Servers = [HTTPS]
|
||||
|
||||
ExpectedReturnCode = 0
|
||||
ExpectedDownloadedFiles = [A_File, B_File, C_File]
|
||||
|
||||
################ Pre and Post Test Hooks #####################################
|
||||
pre_test = {
|
||||
"ServerFiles" : Files,
|
||||
"LocalFiles" : Existing_Files
|
||||
}
|
||||
test_options = {
|
||||
"WgetCommands" : WGET_OPTIONS,
|
||||
"Urls" : WGET_URLS
|
||||
}
|
||||
post_test = {
|
||||
"ExpectedFiles" : ExpectedDownloadedFiles,
|
||||
"ExpectedRetcode" : ExpectedReturnCode
|
||||
}
|
||||
|
||||
err = HTTPTest (
|
||||
name=TEST_NAME,
|
||||
pre_hook=pre_test,
|
||||
test_params=test_options,
|
||||
post_hook=post_test,
|
||||
protocols=Servers
|
||||
).begin ()
|
||||
|
||||
exit (err)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user