Blob


1 #!/bin/sh
3 set -e
5 if [ "${SKIP_RUNTIME_TESTS:-0}" -eq 1 ]; then
6 echo
7 echo "======================"
8 echo "runtime tests skipped!"
9 echo "======================"
10 echo
11 exit 0
12 fi
14 ggflags=
16 config_common='
17 ipv6 off
18 port 10965
19 '
21 # usage: config <global config> <stuff for localhost>
22 # generates a configuration file reg.conf
23 config() {
24 cat <<EOF > reg.conf
25 $config_common
26 $1
27 server "localhost" {
28 cert "$PWD/cert.pem"
29 key "$PWD/key.pem"
30 root "$PWD/testdata"
31 $2
32 }
33 EOF
34 }
36 checkconf() {
37 ./../gmid -n -c reg.conf
38 }
40 # usage: get <path>
41 # return the body of the request on stdout
42 get() {
43 ./gg -T30 -b $ggflags "gemini://localhost:10965/$1"
44 }
46 # usage: head <path>
47 # return the meta response line on stdout
48 head() {
49 ./gg -T30 -h $ggflags "gemini://localhost:10965/$1"
50 }
52 # usage: raw <path>
53 # return both header and body
54 raw() {
55 ./gg -T30 $ggflags "gemini://localhost:10965/$1"
56 }
58 run() {
59 ./../gmid -f -c reg.conf &
60 pid=$!
61 # give gmid time to bind the port, otherwise we end up
62 # executing gg when gmid isn't ready yet.
63 sleep 1
64 }
66 # usage: check [exit-message]
67 # check if gmid is still running
68 check() {
69 if ! ps $pid >/dev/null; then
70 echo ${1:-"gmid crashed?"}
71 exit 1
72 fi
73 }
75 restart() {
76 kill -HUP $pid
77 sleep 1
78 }
80 # quit gmid
81 quit() {
82 kill $pid || true
83 wait || true
84 }
86 count() {
87 wc -l | xargs
88 }
90 # usage: eq a b errmsg
91 # if a and b aren't equal strings, exit with errmsg
92 eq() {
93 if ! [ "$1" = "$2" ]; then
94 echo "$3: \"$1\" not equal \"$2\""
95 exit 1
96 fi
97 }
99 onexit() {
100 rm -f bigfile bigfile.sha
101 quit
104 # tests
106 trap 'onexit' INT TERM EXIT
108 endl=`printf "\r\n"`
109 lf=`echo`
111 config "" ""
112 checkconf
113 run
115 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
116 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
117 echo OK GET /
119 eq "$(head /foo)" "51 not found" "Unexpected head /foo"
120 eq "$(get /foo)" "" "Unexpected body /foo"
121 echo OK GET /foo
123 # should redirect if asked for a directory but without the trailing /
124 eq "$(head /dir)" "30 /dir/" "Unexpected redirect for /dir"
125 eq "$(get /dir)" "" "Unexpected body for redirect"
126 echo OK GET /dir
128 # 51 for a directory without index.gmi
129 eq "$(head /dir/)" "51 not found" "Unexpected head for /"
130 eq "$(get /dir/)" "" "Unexpected body for error"
131 echo OK GET /dir/
133 eq "$(head /dir/foo.gmi)" "20 text/gemini" "Unexpected head for /dir/foo.gmi"
134 eq "$(get /dir/foo.gmi)" "# hello world$ln" "Unexpected body for /dir/foo.gmi"
135 echo OK GET /dir/foo.gmi
137 # try a big file
138 eq "$(head /bigfile)" "20 application/octet-stream" "Unexpected head for /bigfile"
139 get /bigfile > bigfile
140 ./sha bigfile bigfile.sha
141 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /bigfile"
142 echo OK GET /bigfile
144 # shouldn't be executing cgi scripts
145 eq "$(head /hello)" "20 application/octet-stream" "Unexpected head for /hello"
146 echo OK GET /hello
148 check "should be running"
150 # try with custom mime
151 config 'map "text/x-funny-text" to-ext "gmi"' 'default type "application/x-trash"'
152 checkconf
153 restart
155 eq "$(head /)" "20 text/x-funny-text" "Unexpected head for /"
156 echo OK GET / with custom mime
158 eq "$(head /hello)" "20 application/x-trash" "Unexpected head for /hello"
159 echo OK GET /hello with custom mime
161 check "should be running"
163 # try with custom lang
164 config '' 'lang "it"'
165 checkconf
166 restart
168 eq "$(head /)" "20 text/gemini; lang=it" "Unexpected head for /"
169 echo OK GET / with custom lang
171 check "should be running"
173 # make sure we can use different lang in different location rules
174 config '' 'lang "it" location "/en/*" { lang "en" } location "/de/*" { lang "de" }'
175 checkconf
176 echo OK parse multiple locations correctly
177 restart
179 # try with CGI scripts
180 config '' 'cgi "*"'
181 checkconf
182 restart
184 eq "$(head /hello)" "20 text/gemini" "Unexpected head for /hello"
185 eq "$(get /hello)" "# hello world$ln" "Unexpected body for /hello"
186 echo OK GET /hello with cgi
188 eq "$(head /slow)" "20 text/gemini" "Unexpected head for /slow"
189 eq "$(get /slow)" "# hello world$ln" "Unexpected body for /slow"
190 echo OK GET /slow with cgi
192 eq "$(head /err)" "42 CGI error" "Unexpected head for /err"
193 eq "$(get /err)" "" "Unexpected body for /err"
194 echo OK GET /err with cgi
196 eq "$(raw /invalid | wc -c | xargs)" 2048 "Unexpected body for /invalid"
197 echo OK GET /invalid with cgi
199 eq "$(raw /max-length-reply | wc -c | xargs)" 1029 "Unexpected header for /max-length-reply"
200 echo OK GET /max-length-reply with cgi
202 # try a big file
203 eq "$(head /serve-bigfile)" "20 application/octet-stream" "Unexpected head for /serve-bigfile"
204 get /bigfile > bigfile
205 ./sha bigfile bigfile.sha
206 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /serve-bigfile"
207 echo OK GET /serve-bigfile with cgi
209 # ensure we split the query correctly
210 eq "$(get /env | awk /^-/ | count)" 1 "Unexpected number of arguments"
211 eq "$(get /env?foo | awk /^-/ | count)" 2 "Unexpected number of arguments"
212 eq "$(get /env?foo+bar | awk /^-/ | count)" 3 "Unexpected number of arguments"
213 eq "$(get /env?foo+bar=5 | awk /^-/ | count)" 1 "Unexpected number of arguments"
214 eq "$(get /env?foo+bar%3d5 | awk /^-/ | count)" 3 "Unexpected number of arguments"
216 check "should be running"
218 config '' 'index "foo.gmi"'
219 checkconf
220 restart
222 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /"
223 eq "$(get /dir/)" "# hello world$ln" "Unexpected body for error"
224 echo OK GET /dir/ with custom index
226 check "should be running"
228 config '' 'location "/dir/*" { default type "text/plain" index "hello" }'
229 checkconf
230 restart
232 eq "$(head /dir/hello)" "20 text/plain" "Unexpected head for /"
233 echo OK GET /dir/hello with location and default type
235 eq "$(head /dir/)" "20 text/plain" "Unexpected head for /dir/"
236 eq "$(get /dir/|tail -1)" 'echo "# hello world"' "Unexpected body for /dir/"
237 echo OK GET /dir/ with location and custom index
239 check "should be running"
241 config '' 'location "/dir/*" { auto index on }'
242 checkconf
243 restart
245 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
246 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
247 echo OK GET / with auto index
249 eq "$(head /dir)" "30 /dir/" "Unexpected head for /dir"
250 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /dir/"
251 eq "$(get /dir/|wc -l|xargs)" "5" "Unexpected body for /dir/"
252 echo OK GET /dir/ with auto index on
254 check "should be running"
256 # test block return and strip
258 config '' 'location "*" { block }'
259 checkconf
260 restart
262 eq "$(head /)" "40 temporary failure" "Unexpected head for /"
263 eq "$(get /)" "" "Unexpected body for /"
264 echo OK GET / with block
266 eq "$(head /nonexists)" "40 temporary failure" "Unexpected head for /nonexists"
267 eq "$(get /nonexists)" "" "Unexpected body for /nonexists"
268 echo OK GET /nonexists with block
270 check "should be running"
272 config '' '
273 location "/dir" {
274 strip 1
275 block return 40 "%% %p %q %P %N test"
277 location "*" {
278 strip 99
279 block return 40 "%% %p %q %P %N test"
280 }'
281 checkconf
282 restart
284 eq "$(head /dir/foo.gmi)" "40 % /foo.gmi 10965 localhost test"
285 echo OK GET /dir/foo.gmi with strip and block
287 eq "$(head /bigfile)" "40 % / 10965 localhost test"
288 echo OK GET /bigfile with strip and block
290 check "should be running"
292 # test the entrypoint
294 config '' 'entrypoint "/env"'
295 checkconf
296 restart
298 eq "$(head /foo/bar)" "20 text/plain; lang=en" "Unknown head for /foo/bar"
299 eq "$(get /foo/bar|grep PATH_INFO)" "PATH_INFO=/foo/bar" "Unexpected PATH_INFO"
300 echo OK GET /foo/bar with entrypoint
302 # test with require ca
304 config '' 'require client ca "'$PWD'/testca.pem"'
305 checkconf
306 restart
308 eq "$(head /)" "60 client certificate required" "Unexpected head for /"
309 echo OK GET / without client certificate
311 ggflags="-C valid.crt -K valid.key"
312 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
313 echo OK GET / with valid client certificate
315 ggflags="-C invalid.cert.pem -K invalid.key.pem"
316 eq "$(head /)" "61 certificate not authorised" "Unexpected head for /"
317 echo OK GET / with invalid client certificate
319 ggflags=''
322 # test with root inside a location
324 config '' 'location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
325 checkconf
326 restart
328 eq "$(head /foo)" "51 not found" "Unexpected head for /foo"
329 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
330 echo OK /foo and /foo/ with root inside location
332 # how to match both /foo and /foo/*
333 config '' '
334 location "/foo" { block return 31 "%p/" }
335 location "/foo/*" { root "'$PWD'/testdata" strip 1 }
337 checkconf
338 restart
340 eq "$(head /foo)" "31 /foo/" "Unexpected head for /foo"
341 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
342 echo OK /foo and /foo/ with root inside location
344 # test with fastcgi
346 # NB: the fcgi spawn is NOT supported outside of this test suite
348 config 'prefork 1' 'fastcgi spawn "'$PWD'/fcgi-test"'
349 checkconf
350 restart
352 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
353 eq "$(get /)" "# Hello, world!" "Unexpected body for /"
354 echo OK GET / with fastcgi
356 # test macro expansion
358 cat <<EOF > reg.conf
359 pwd = "$PWD"
360 $config_common
362 server "localhost" {
363 # the quoting of \$ is for sh
364 cert \$pwd "/cert.pem"
365 key \$pwd "/key.pem"
366 root \$pwd "/testdata"
368 EOF
369 checkconf
370 restart
372 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
373 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
374 echo OK GET / with macro expansion