3 # Copyright 2016 - 2023 Paul Hänsch
5 # This file is part of cgilite.
7 # cgilite is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
12 # cgilite is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with cgilite. If not, see <http://www.gnu.org/licenses/>.
20 [ -n "$include_fileserve" ] && return 0
21 include_fileserve="$0"
25 css) printf 'text/css';;
26 gif) printf 'image/gif';;
27 html|html) printf 'text/html';;
28 jpg|jpeg) printf 'image/jpeg';;
29 js) printf 'text/javascript';;
30 m3u8) printf 'application/x-mpegURL';;
31 m4a) printf 'audio/mp4';;
32 m4s) printf 'video/iso.segment';;
33 m4v|mp4) printf 'video/mp4';;
34 mpd) printf 'application/dash+xml';;
35 ogg) printf 'audio/ogg';;
36 pdf) printf 'application/pdf';;
37 png) printf 'image/png';;
38 sh) printf 'text/x-shellscript';;
39 svg) printf 'image/svg+xml';;
40 tex) printf 'text/x-tex';;
41 txt) printf 'text/plain';;
42 short) printf 'text/prs.shorthand';;
43 ts) printf 'video/MP2T';;
44 webm) printf 'video/webm';;
45 xml) printf 'application/xml';;
46 *) printf 'application/octet-stream';;
51 local file="$1" mime="$2"
52 local file_size file_date http_date cachedate range
54 if ! [ -f "$file" ]; then
55 printf 'Content-Length: 0\r\nStatus: 404 Not Found\r\n\r\n'
57 elif ! [ -r "$file" ]; then
58 printf 'Content-Length: 0\r\nStatus: 403 Forbidden\r\n\r\n'
62 read file_size file_date <<-EOF
63 $(stat -Lc "%s %Y" "$file")
65 http_date="$(date -ud "@$file_date" +"%a, %d %b %Y %T GMT")"
67 [ ! "$HTTP_IF_MODIFIED_SINCE" -a "$cgilite_headers" ] \
68 && HTTP_IF_MODIFIED_SINCE="$(HEADER If-Modified-Since)"
69 [ ! "$HTTP_RANGE" -a "$cgilite_headers" ] \
70 && HTTP_RANGE="$(HEADER Range)"
73 # Parse the allowable date formats from Section 3.3.1 of
74 # https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
75 # HEADER If-Modified-Since \
76 printf %s "$HTTP_IF_MODIFIED_SINCE" \
77 | sed -E 's;^[^ ]+, ([0-9]{2}) (...) ([0-9]{4}) (..:..:..) GMT$;\3-\2-\1 \4;;
78 s;^[^ ]+, ([0-9]{2})-(...)-([789][0-9]) (..:..:..) GMT$;19\3-\2-\1 \4;;
79 s;^[^ ]+, ([0-9]{2})-(...)-([0-6][0-9]) (..:..:..) GMT$;20\3-\2-\1 \4;;
80 s;^[^ ]+ (...) ([0-9]{2}) (..:..:..) ([0-9]{4})$;\4-\1-\2 \3;;
81 s;^[^ ]+ (...) ([0-9]) (..:..:..) ([0-9]{4})$;\4-\1-\2 \3;;
82 s;Jan;01;; s;Feb;02;; s;Mar;03;; s;Apr;04;; s;May;05;; s;Jun;06;;
83 s;Jul;07;; s;Aug;08;; s;Sep;09;; s;Oct;10;; s;Nov;11;; s;Dec;12;;' \
84 | xargs -r0 date +%s -ud 2>&-
87 range="${HTTP_RANGE#bytes=}"
89 *[^0-9]*-*|*-*[^0-9]*)
93 range="${range}$((file_size - 1))"
96 [ ${range#-} -le $file_size ] \
97 && range="$((file_size - ${range#-}))-$((file_size - 1))" \
98 || range="0-$((file_size - 1))"
101 [ ${range#*-} -ge $file_size ] \
102 && range="${range%-*}-$((file_size - 1))"
108 if [ "$file_date" -lt "$cachedate" ] 2>&-; then
109 printf '%s: %s\r\n' \
110 Status '304 Not Modified' \
112 Last-Modified "$http_date"
115 elif [ -z "$range" ]; then
116 printf '%s: %s\r\n' \
118 Accept-Ranges bytes \
119 Last-Modified "$http_date" \
120 Content-Type "${mime:-$(file_type "$file")}" \
121 Content-Length $file_size
124 [ "$REQUEST_METHOD" != HEAD ] && cat "$file"
126 elif [ "${range%-*}" -le "${range#*-}" ]; then
127 printf '%s: %s\r\n' \
128 Status "206 Partial Content" \
129 Accept-Ranges bytes \
130 Last-Modified "$http_date" \
131 Content-Type "${mime:-$(file_type "$file")}" \
132 Content-Range "bytes ${range}/${file_size}" \
133 Content-Length "$((${range#*-} - ${range%-*} + 1))"
136 [ "$REQUEST_METHOD" != HEAD ] \
137 && tail -c+$((${range%-*} + 1)) "$file" \
138 | head -c "$((${range#*-} - ${range%-*} + 1))"
140 elif [ "${range%-*}" -gt "${range#*-}" ]; then
141 printf '%s: %s\r\n' \
142 Status "216 Range Not Satisfiable" \
144 Content-Range \*/${file_size}