Blob


1 #!/bin/sh
3 set -e
5 ggflags=
7 config_common='
8 ipv6 off
9 port 10965
10 '
12 # usage: config <global config> <stuff for localhost>
13 # generates a configuration file reg.conf
14 config() {
15 cat <<EOF > reg.conf
16 $config_common
17 $1
18 server "localhost" {
19 cert "$PWD/cert.pem"
20 key "$PWD/key.pem"
21 root "$PWD/testdata"
22 $2
23 }
24 EOF
25 }
27 checkconf() {
28 ./../gmid -n -c reg.conf
29 }
31 # usage: get <path>
32 # return the body of the request on stdout
33 get() {
34 ./gg -T30 -b $ggflags "gemini://localhost:10965/$1"
35 }
37 # usage: head <path>
38 # return the meta response line on stdout
39 head() {
40 ./gg -T30 -h $ggflags "gemini://localhost:10965/$1"
41 }
43 # usage: raw <path>
44 # return both header and body
45 raw() {
46 ./gg -T30 $ggflags "gemini://localhost:10965/$1"
47 }
49 run() {
50 ./../gmid -f -c reg.conf &
51 pid=$!
52 # give gmid time to bind the port, otherwise we end up
53 # executing gg when gmid isn't ready yet.
54 sleep 1
55 }
57 # usage: check [exit-message]
58 # check if gmid is still running
59 check() {
60 if ! ps $pid >/dev/null; then
61 echo ${1:-"gmid crashed?"}
62 exit 1
63 fi
64 }
66 restart() {
67 kill -HUP $pid
68 sleep 1
69 }
71 # quit gmid
72 quit() {
73 kill $pid || true
74 wait || true
75 }
77 count() {
78 wc -l | xargs
79 }
81 # usage: eq a b errmsg
82 # if a and b aren't equal strings, exit with errmsg
83 eq() {
84 if ! [ "$1" = "$2" ]; then
85 echo "$3: \"$1\" not equal \"$2\""
86 exit 1
87 fi
88 }
90 onexit() {
91 rm -f bigfile bigfile.sha
92 quit
93 }
95 # tests
97 trap 'onexit' INT TERM EXIT
99 endl=`printf "\r\n"`
100 lf=`echo`
102 config "" ""
103 checkconf
104 run
106 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
107 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
108 echo OK GET /
110 eq "$(head /foo)" "51 not found" "Unexpected head /foo"
111 eq "$(get /foo)" "" "Unexpected body /foo"
112 echo OK GET /foo
114 # should redirect if asked for a directory but without the trailing /
115 eq "$(head /dir)" "30 /dir/" "Unexpected redirect for /dir"
116 eq "$(get /dir)" "" "Unexpected body for redirect"
117 echo OK GET /dir
119 # 51 for a directory without index.gmi
120 eq "$(head /dir/)" "51 not found" "Unexpected head for /"
121 eq "$(get /dir/)" "" "Unexpected body for error"
122 echo OK GET /dir/
124 eq "$(head /dir/foo.gmi)" "20 text/gemini" "Unexpected head for /dir/foo.gmi"
125 eq "$(get /dir/foo.gmi)" "# hello world$ln" "Unexpected body for /dir/foo.gmi"
126 echo OK GET /dir/foo.gmi
128 # try a big file
129 eq "$(head /bigfile)" "20 application/octet-stream" "Unexpected head for /bigfile"
130 get /bigfile > bigfile
131 ./sha bigfile bigfile.sha
132 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /bigfile"
133 echo OK GET /bigfile
135 # shouldn't be executing cgi scripts
136 eq "$(head /hello)" "20 application/octet-stream" "Unexpected head for /hello"
137 echo OK GET /hello
139 check "should be running"
141 # try with custom mime
142 config 'mime "text/x-funny-text" "gmi"' 'default type "application/x-trash"'
143 checkconf
144 restart
146 eq "$(head /)" "20 text/x-funny-text" "Unexpected head for /"
147 echo OK GET / with custom mime
149 eq "$(head /hello)" "20 application/x-trash" "Unexpected head for /hello"
150 echo OK GET /hello with custom mime
152 check "should be running"
154 # try with custom lang
155 config '' 'lang "it"'
156 checkconf
157 restart
159 eq "$(head /)" "20 text/gemini; lang=it" "Unexpected head for /"
160 echo OK GET / with custom lang
162 check "should be running"
164 # make sure we can use different lang in different location rules
165 config '' 'lang "it" location "/en/*" { lang "en" } location "/de/*" { lang "de" }'
166 checkconf
167 echo OK parse multiple locations correctly
168 restart
170 # try with CGI scripts
171 config '' 'cgi "*"'
172 checkconf
173 restart
175 eq "$(head /hello)" "20 text/gemini" "Unexpected head for /hello"
176 eq "$(get /hello)" "# hello world$ln" "Unexpected body for /hello"
177 echo OK GET /hello with cgi
179 eq "$(head /slow)" "20 text/gemini" "Unexpected head for /slow"
180 eq "$(get /slow)" "# hello world$ln" "Unexpected body for /slow"
181 echo OK GET /slow with cgi
183 eq "$(head /err)" "42 CGI error" "Unexpected head for /err"
184 eq "$(get /err)" "" "Unexpected body for /err"
185 echo OK GET /err with cgi
187 eq "$(raw /invalid | wc -c | xargs)" 2048 "Unexpected body for /invalid"
188 echo OK GET /invalid with cgi
190 eq "$(raw /max-length-reply | wc -c | xargs)" 1029 "Unexpected header for /max-length-reply"
191 echo OK GET /max-length-reply with cgi
193 # try a big file
194 eq "$(head /serve-bigfile)" "20 application/octet-stream" "Unexpected head for /serve-bigfile"
195 get /bigfile > bigfile
196 ./sha bigfile bigfile.sha
197 eq "$(cat bigfile.sha)" "$(cat testdata/bigfile.sha)" "Unexpected sha for /serve-bigfile"
198 echo OK GET /serve-bigfile with cgi
200 # ensure we split the query correctly
201 eq "$(get /env | awk /^-/ | count)" 1 "Unexpected number of arguments"
202 eq "$(get /env?foo | awk /^-/ | count)" 2 "Unexpected number of arguments"
203 eq "$(get /env?foo+bar | awk /^-/ | count)" 3 "Unexpected number of arguments"
204 eq "$(get /env?foo+bar=5 | awk /^-/ | count)" 1 "Unexpected number of arguments"
205 eq "$(get /env?foo+bar%3d5 | awk /^-/ | count)" 3 "Unexpected number of arguments"
207 check "should be running"
209 config '' 'index "foo.gmi"'
210 checkconf
211 restart
213 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /"
214 eq "$(get /dir/)" "# hello world$ln" "Unexpected body for error"
215 echo OK GET /dir/ with custom index
217 check "should be running"
219 config '' 'location "/dir/*" { default type "text/plain" index "hello" }'
220 checkconf
221 restart
223 eq "$(head /dir/hello)" "20 text/plain" "Unexpected head for /"
224 echo OK GET /dir/hello with location and default type
226 eq "$(head /dir/)" "20 text/plain" "Unexpected head for /dir/"
227 eq "$(get /dir/|tail -1)" 'echo "# hello world"' "Unexpected body for /dir/"
228 echo OK GET /dir/ with location and custom index
230 check "should be running"
232 config '' 'location "/dir/*" { auto index on }'
233 checkconf
234 restart
236 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
237 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
238 echo OK GET / with auto index
240 eq "$(head /dir)" "30 /dir/" "Unexpected head for /dir"
241 eq "$(head /dir/)" "20 text/gemini" "Unexpected head for /dir/"
242 eq "$(get /dir/|wc -l|xargs)" "5" "Unexpected body for /dir/"
243 echo OK GET /dir/ with auto index on
245 check "should be running"
247 # test block return and strip
249 config '' 'location "*" { block }'
250 checkconf
251 restart
253 eq "$(head /)" "40 temporary failure" "Unexpected head for /"
254 eq "$(get /)" "" "Unexpected body for /"
255 echo OK GET / with block
257 eq "$(head /nonexists)" "40 temporary failure" "Unexpected head for /nonexists"
258 eq "$(get /nonexists)" "" "Unexpected body for /nonexists"
259 echo OK GET /nonexists with block
261 check "should be running"
263 config '' '
264 location "/dir" {
265 strip 1
266 block return 40 "%% %p %q %P %N test"
268 location "*" {
269 strip 99
270 block return 40 "%% %p %q %P %N test"
271 }'
272 checkconf
273 restart
275 eq "$(head /dir/foo.gmi)" "40 % /foo.gmi 10965 localhost test"
276 echo OK GET /dir/foo.gmi with strip and block
278 eq "$(head /bigfile)" "40 % / 10965 localhost test"
279 echo OK GET /bigfile with strip and block
281 check "should be running"
283 # test the entrypoint
285 config '' 'entrypoint "/env"'
286 checkconf
287 restart
289 eq "$(head /foo/bar)" "20 text/plain; lang=en" "Unknown head for /foo/bar"
290 eq "$(get /foo/bar|grep PATH_INFO)" "PATH_INFO=/foo/bar" "Unexpected PATH_INFO"
291 echo OK GET /foo/bar with entrypoint
293 # test with require ca
295 config '' 'require client ca "'$PWD'/testca.pem"'
296 checkconf
297 restart
299 eq "$(head /)" "60 client certificate required" "Unexpected head for /"
300 echo OK GET / without client certificate
302 ggflags="-C valid.crt -K valid.key"
303 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
304 echo OK GET / with valid client certificate
306 ggflags="-C invalid.cert.pem -K invalid.key.pem"
307 eq "$(head /)" "61 certificate not authorised" "Unexpected head for /"
308 echo OK GET / with invalid client certificate
310 ggflags=''
313 # test with root inside a location
315 config '' 'location "/foo/*" { root "'$PWD'/testdata" strip 1 }'
316 checkconf
317 restart
319 eq "$(head /foo)" "51 not found" "Unexpected head for /foo"
320 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
321 echo OK /foo and /foo/ with root inside location
323 # how to match both /foo and /foo/*
324 config '' '
325 location "/foo" { block return 31 "%p/" }
326 location "/foo/*" { root "'$PWD'/testdata" strip 1 }
328 checkconf
329 restart
331 eq "$(head /foo)" "31 /foo/" "Unexpected head for /foo"
332 eq "$(head /foo/)" "20 text/gemini" "Unexpected head for /foo/"
333 echo OK /foo and /foo/ with root inside location
335 # test with fastcgi
337 # NB: the fcgi spawn is NOT supported outside of this test suite
339 config 'prefork 1' 'fastcgi spawn "'$PWD'/fcgi-test"'
340 checkconf
341 restart
343 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
344 eq "$(get /)" "# Hello, world!" "Unexpected body for /"
345 echo OK GET / with fastcgi
347 # test macro expansion
349 cat <<EOF > reg.conf
350 pwd = "$PWD"
351 $config_common
353 server "localhost" {
354 # the quoting of \$ is for sh
355 cert \$pwd "/cert.pem"
356 key \$pwd "/key.pem"
357 root \$pwd "/testdata"
359 EOF
360 checkconf
361 restart
363 eq "$(head /)" "20 text/gemini" "Unexpected head for /"
364 eq "$(get /)" "# hello world$ln" "Unexpected body for /"
365 echo OK GET / with macro expansion