Repository navigation
Expand file tree
/
Copy pathhttp_ftp_test.sh
More file actions
191 lines (178 loc) · 6.28 KB
/
Copy pathhttp_ftp_test.sh
File metadata and controls
191 lines (178 loc) · 6.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# Tests for the ftp(1) branch of http_download.
#
# ftp(1) is the base-system downloader on OpenBSD and NetBSD; neither ships
# curl or wget. These live in their own file because they stub `ftp` as a
# shell function, which would shadow the real one and break the live-network
# tests in http_download_test.sh.
#
# Two different programs answer to the name `ftp`, and they differ in the one
# way that matters here: tnftp (NetBSD, DragonFly) has -H for arbitrary
# request headers, OpenBSD's ftp has no header support at all. The library
# probes the binary's usage line rather than trusting `uname -s`, so the stub
# below emulates both usage lines and STUB_FTP_HAS_H selects which.
#
# Accept is a special case in BOTH: tnftp always sends its own "Accept: */*"
# first, so an -H Accept is delivered but never wins. The library refuses it
# rather than returning the wrong representation.
#
# shellcheck disable=SC1091,SC2034,SC2329
. ./assert.sh
. ./is_command.sh
. ./echoerr.sh
. ./log.sh
. ./mktmpdir.sh
. ./http_download.sh
# "yes" makes the stub advertise tnftp's -H; "no" makes it OpenBSD's ftp.
#
# Driven by a variable rather than by redefining the stub per test: ksh93
# does not honour a function redefined inside a subshell, and repeatedly
# redefining and unsetting functions has made it crash.
STUB_FTP_HAS_H="no"
STUB_FTP_ARGS=""
STUB_FTP_HEADER=""
# stand in for ftp(1): answer the capability probe, otherwise record how it
# was called and write the output file
ftp() {
# the probe. -Z is not a valid option in either real program, so both
# print their usage line and exit.
if [ "$1" = "-Z" ]; then
if [ "$STUB_FTP_HAS_H" = "yes" ]; then
echo "usage: ftp [-46AadefginpRtVv] [-b BUFSIZE] [-H HEADER] [-N NETRC] [-o OUTPUT]" >&2
else
echo "usage: ftp [-46AadEegiMmnptVv] [-D title] [-k seconds] [-o output]" >&2
fi
return 1
fi
STUB_FTP_ARGS="$*"
STUB_FTP_HEADER=""
_out=""
_prev=""
for _a in "$@"; do
if [ "$_prev" = "-o" ]; then _out=$_a; fi
if [ "$_prev" = "-H" ]; then STUB_FTP_HEADER=$_a; fi
_prev=$_a
done
test -z "$_out" || echo stub >"$_out"
return 0
}
test_plain_download() {
d=$(mktmpdir)
http_download_ftp "$d/f" https://example.invalid/x
assertEquals "0" "$?" "ftp: plain download returns 0"
assertTrue "[ -f '$d/f' ]" "ftp: writes the output file"
assertEquals "" "$STUB_FTP_HEADER" "ftp: no header sent when none given"
rm -rf "$d"
}
# -V is the only flag both programs accept for "be quiet"; OpenBSD's -M does
# not exist in tnftp.
test_plain_download_is_quiet() {
d=$(mktmpdir)
http_download_ftp "$d/f" https://example.invalid/x
case "$STUB_FTP_ARGS" in
*-V*) assertTrue "true" "ftp: passes -V" ;;
*) assertTrue "false" "ftp: did not pass -V (args=[$STUB_FTP_ARGS])" ;;
esac
rm -rf "$d"
}
# tnftp: -H carries an ordinary header through verbatim
test_header_with_tnftp() {
STUB_FTP_HAS_H="yes"
d=$(mktmpdir)
http_download_ftp "$d/f" https://example.invalid/x "X-Shlib-Test: 1"
assertEquals "0" "$?" "ftp: header download returns 0 when -H is supported"
assertEquals "X-Shlib-Test: 1" "$STUB_FTP_HEADER" "ftp: header passed via -H"
STUB_FTP_HAS_H="no"
rm -rf "$d"
}
test_authorization_with_tnftp() {
STUB_FTP_HAS_H="yes"
d=$(mktmpdir)
http_download_ftp "$d/f" https://example.invalid/x "Authorization: token abc"
assertEquals "Authorization: token abc" "$STUB_FTP_HEADER" "ftp: Authorization passed via -H"
STUB_FTP_HAS_H="no"
rm -rf "$d"
}
# Accept is refused even where -H exists.
#
# tnftp writes its own "Accept: */*" ahead of any -H header and nothing
# suppresses it, so the request carries two and the server answers the first.
# That is how the NetBSD leg got GitHub's HTML release page while asking for
# JSON. Delivering a header that cannot take effect is worse than refusing.
test_accept_refused_even_with_h() {
STUB_FTP_HAS_H="yes"
d=$(mktmpdir)
STUB_FTP_HEADER=""
STUB_FTP_ARGS=""
assertFalse "http_download_ftp '$d/f' https://example.invalid/x 'Accept:application/json'" \
"ftp: Accept refused even when -H is available"
assertEquals "" "$STUB_FTP_ARGS" "ftp: no request made when Accept cannot take effect"
STUB_FTP_HAS_H="no"
rm -rf "$d"
}
test_accept_refused_lowercase() {
STUB_FTP_HAS_H="yes"
d=$(mktmpdir)
STUB_FTP_ARGS=""
assertFalse "http_download_ftp '$d/f' https://example.invalid/x 'accept: application/json'" \
"ftp: Accept refused case-insensitively"
STUB_FTP_HAS_H="no"
rm -rf "$d"
}
# OpenBSD's ftp has no -H at all. Failing loudly beats silently dropping the
# header -- github_api without its Authorization would get an unauthenticated
# request.
test_header_without_h_fails() {
STUB_FTP_HAS_H="no"
d=$(mktmpdir)
STUB_FTP_HEADER=""
assertFalse "http_download_ftp '$d/f' https://example.invalid/x 'Authorization: token abc'" \
"ftp: unsupported header fails rather than being dropped"
assertEquals "" "$STUB_FTP_HEADER" "ftp: no request made when the header cannot be sent"
rm -rf "$d"
}
# on a stock OpenBSD or NetBSD box there is no curl, no wget and no fetch
test_dispatch_falls_through_to_ftp() {
is_command() {
case "$1" in
curl | wget | fetch) return 1 ;;
*) command -v "$1" >/dev/null ;;
esac
}
d=$(mktmpdir)
STUB_FTP_ARGS=""
http_download "$d/f" https://example.invalid/x >/dev/null 2>&1
case "$STUB_FTP_ARGS" in
*example.invalid*) assertTrue "true" "dispatch: uses ftp when curl, wget and fetch are absent" ;;
*) assertTrue "false" "dispatch: did not reach ftp (args=[$STUB_FTP_ARGS])" ;;
esac
. ./is_command.sh
rm -rf "$d"
}
# fetch wins over ftp. DragonFly has both, and fetch is the one that can
# express an Accept header there.
test_dispatch_prefers_fetch() {
is_command() {
case "$1" in
curl | wget) return 1 ;;
fetch) return 0 ;;
*) command -v "$1" >/dev/null ;;
esac
}
fetch() { return 0; }
d=$(mktmpdir)
STUB_FTP_ARGS=""
http_download "$d/f" https://example.invalid/x >/dev/null 2>&1
assertEquals "" "$STUB_FTP_ARGS" "dispatch: fetch is preferred over ftp when available"
. ./is_command.sh
unset -f fetch
rm -rf "$d"
}
test_plain_download
test_plain_download_is_quiet
test_header_with_tnftp
test_authorization_with_tnftp
test_accept_refused_even_with_h
test_accept_refused_lowercase
test_header_without_h_fails
test_dispatch_falls_through_to_ftp
test_dispatch_prefers_fetch