8
8
# Reworked by: Josh Cartwright, 2012
9
9
# Reworked by: Nathan Rajlich, 2018
10
10
11
- # If running as `root`, then downgrade to `nobody` first
12
- if [ " $EUID " -eq 0 ]; then
13
- exec sudo -u nobody " $0 " " $@ "
14
- fi
15
-
16
11
conf=" ${BASHTTPD_CONFIG-bashttpd.conf} "
17
12
18
- [ -r " ${conf} " ] || {
19
- cat > " ${conf} " << 'EOF '
20
- #
21
- # bashttpd.conf - configuration for bashttpd
22
- #
23
- # The behavior of bashttpd is dictated by the evaluation
24
- # of rules specified in this configuration file. Each rule
25
- # is evaluated until one is matched. If no rule is matched,
26
- # bashttpd will serve a 500 Internal Server Error.
27
- #
28
- # The format of the rules are:
29
- # on_uri_match REGEX command [args]
30
- # unconditionally command [args]
31
- #
32
- # on_uri_match:
33
- # On an incoming request, the URI is checked against the specified
34
- # (bash-supported extended) regular expression, and if encounters a match the
35
- # specified command is executed with the specified arguments.
36
- #
37
- # For additional flexibility, on_uri_match will also pass the results of the
38
- # regular expression match, ${BASH_REMATCH[@]} as additional arguments to the
39
- # command.
40
- #
41
- # unconditionally:
42
- # Always serve via the specified command. Useful for catchall rules.
43
- #
44
- # The following commands are available for use:
45
- #
46
- # serve_file FILE
47
- # Statically serves a single file.
48
- #
49
- # serve_dir_with_tree DIRECTORY
50
- # Statically serves the specified directory using 'tree'. It must be
51
- # installed and in the PATH.
52
- #
53
- # serve_dir_with_ls DIRECTORY
54
- # Statically serves the specified directory using 'ls -al'.
55
- #
56
- # serve_dir DIRECTORY
57
- # Statically serves a single directory listing. Will use 'tree' if it is
58
- # installed and in the PATH, otherwise, 'ls -al'
59
- #
60
- # serve_dir_or_file_from DIRECTORY
61
- # Serves either a directory listing (using serve_dir) or a file (using
62
- # serve_file). Constructs local path by appending the specified root
63
- # directory, and the URI portion of the client request.
64
- #
65
- # serve_static_string STRING
66
- # Serves the specified static string with Content-Type text/plain.
67
- #
68
- # Examples of rules:
69
- #
70
- # on_uri_match '^/issue$' serve_file "/etc/issue"
71
- #
72
- # When a client's requested URI matches the string '/issue', serve them the
73
- # contents of /etc/issue
74
- #
75
- # on_uri_match 'root' serve_dir /
76
- #
77
- # When a client's requested URI has the word 'root' in it, serve up
78
- # a directory listing of /
79
- #
80
- # DOCROOT=/var/www/html
81
- # on_uri_match '/(.*)' serve_dir_or_file_from "$DOCROOT"
82
- # When any URI request is made, attempt to serve a directory listing
83
- # or file content based on the request URI, by mapping URI's to local
84
- # paths relative to the specified "$DOCROOT"
85
- #
86
-
87
- unconditionally serve_static_string 'Hello, world! You can configure bashttpd by modifying bashttpd.conf.'
88
-
89
- # More about commands:
90
- #
91
- # It is possible to somewhat easily write your own commands. An example
92
- # may help. The following example will serve "Hello, $x!" whenever
93
- # a client sends a request with the URI /say_hello_to/$x:
94
- #
95
- # serve_hello() {
96
- # set_response_header "Content-Type" "text/plain"
97
- # echo "Hello, $2!"
98
- # }
99
- # on_uri_match '^/say_hello_to/(.*)$' serve_hello
100
- #
101
- # Like mentioned before, the contents of ${BASH_REMATCH[@]} are passed
102
- # to your command, so its possible to use regular expression groups
103
- # to pull out info.
104
- #
105
- # With this example, when the requested URI is /say_hello_to/Josh, serve_hello
106
- # is invoked with the arguments '/say_hello_to/Josh' 'Josh',
107
- # (${BASH_REMATCH[0]} is always the full match)
108
- EOF
109
- echo " Created bashttpd.conf using defaults."
110
- echo " Please review it/configure before running bashttpd again."
111
- exit 1
112
- }
113
-
114
13
recv () { echo " <" " $@ " >&2 ; }
115
14
send () { echo " >" " $@ " >&2 ;
116
15
printf " %s\r\n" " $* " ; }
@@ -296,86 +195,6 @@ fail_with() {
296
195
return 1
297
196
}
298
197
299
- serve_file () {
300
- local file=" $1 "
301
- local length=" $( stat -c' %s' " $file " ) "
302
- if [ $? -ne 0 ]; then
303
- fail_with 404
304
- else
305
- CONTENT_TYPE=
306
- case " $file " in
307
- * \. css)
308
- CONTENT_TYPE=" text/css"
309
- ;;
310
- * \. js)
311
- CONTENT_TYPE=" text/javascript"
312
- ;;
313
- * )
314
- CONTENT_TYPE=" $( file -b --mime-type " $file " ) "
315
- ;;
316
- esac
317
-
318
- set_response_header " Content-Type" " $CONTENT_TYPE "
319
-
320
- read -r CONTENT_LENGTH < <( stat -c' %s' " $file " ) && \
321
- set_response_header " Content-Length" " $CONTENT_LENGTH "
322
-
323
- cat " $file "
324
- fi
325
- }
326
-
327
- serve_dir_with_tree () {
328
- local dir=" $1 " tree_vers tree_opts basehref x
329
-
330
- set_response_header " Content-Type" " text/html"
331
-
332
- # The --du option was added in 1.6.0.
333
- read x tree_vers x < <( tree --version)
334
- [[ $tree_vers == v1.6* ]] && tree_opts=" --du"
335
-
336
- tree -H " $2 " -L 1 " $tree_opts " -D " $dir "
337
- }
338
-
339
- serve_dir_with_ls () {
340
- local dir=$1
341
- set_response_header " Content-Type" " text/plain"
342
- ls -la " $dir "
343
- }
344
-
345
- serve_dir () {
346
- # If `tree` is installed, use that for pretty output.
347
- if which tree & > /dev/null; then
348
- serve_dir_with_tree " $@ "
349
- else
350
- serve_dir_with_ls " $@ "
351
- fi
352
- }
353
-
354
- serve_dir_or_file_from () {
355
- local root=" $1 "
356
- local file=" ${3-${2-} } "
357
- local URL_PATH=" ${root} /${file} "
358
-
359
- # sanitize URL_PATH
360
- URL_PATH=${URL_PATH// [^a-zA-Z0-9_~\-\.\/]/ }
361
- [[ $URL_PATH == * ..* ]] && fail_with 400
362
-
363
- # Serve index file if exists in requested directory
364
- [[ -d $URL_PATH && -f $URL_PATH /index.html && -r $URL_PATH /index.html ]] && \
365
- URL_PATH=" $URL_PATH /index.html"
366
-
367
- if [[ -f $URL_PATH ]] && [[ -r $URL_PATH ]]; then
368
- serve_file " $URL_PATH " " $@ "
369
- elif [[ -d $URL_PATH ]] && [[ -x $URL_PATH ]]; then
370
- serve_dir " $URL_PATH " " $@ "
371
- fi
372
- }
373
-
374
- serve_static_string () {
375
- set_response_header " Content-Type" " text/plain"
376
- echo " $1 "
377
- }
378
-
379
198
# https://stackoverflow.com/a/37840948/376773
380
199
decode_url () { : " ${*// +/ } " ; echo -e " ${_//%/ \\ x} " ; }
381
200
@@ -394,7 +213,7 @@ get_request_header() {
394
213
return 1
395
214
}
396
215
397
- get_request_body () {
216
+ parse_request_body () {
398
217
local length=" $( get_request_header " content-length" ) "
399
218
if [ ! -z " ${length} " ]; then
400
219
recv " Reading ${length} byte request body"
@@ -426,18 +245,8 @@ get_request_body() {
426
245
fi
427
246
}
428
247
429
- on_uri_match () {
430
- local regex=$1
431
- shift
432
- [[ $REQUEST_URI =~ $regex ]] && " $@ " " ${BASH_REMATCH[@]} "
433
- }
434
-
435
- unconditionally () {
436
- " $@ " " $REQUEST_URI "
437
- }
438
-
439
248
run_user_code () {
440
249
source " ${conf} "
441
250
}
442
251
443
- get_request_body | run_user_code | flush_response
252
+ parse_request_body | run_user_code | flush_response
0 commit comments