blob: 20cbcf60b4d69967c7dfb3c2365e000624cc6375 (
plain)
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
|
#! /bin/sh
# vim:set fdm=marker:
set -euf
Server='htgen-plain/1.0'
## htgen --serve {{{
case $# in
(1)
case "$1" in
(--serve)
HTGEN_HOST="${HTGEN_HOST-0.0.0.0}"
HTGEN_PORT="${HTGEN_PORT-42380}"
TCPSERVER_OPTS='-c 423 -t 2 -D'
echo "#### $Server $HTGEN_HOST:$HTGEN_PORT" >&2
exec tcpserver $TCPSERVER_OPTS "$HTGEN_HOST" "$HTGEN_PORT" "$0"
## this should not happen...
exit 23
esac
esac
## }}}
## reply_404 {{{
reply_404() {
cat<<EOF
HTTP/1.0 404 Not Found
Content-Type: text/plain; charset=UTF-8
Server: $Server
Connection: close
Content-Length: 0
EOF
}
## }}}
## date. {{{
#date=`date --rfc-3339=ns`
date="`date '+%Y-%m-%d %H:%M:%S'`"
cat>&2<<EOF
# ${TCPREMOTEHOST-}[$TCPREMOTEIP]:$TCPREMOTEPORT connected at $date over $PROTO
EOF
## }}}
## Parse Request-Line. {{{
read Request_Line
eval "$(echo "$Request_Line" | sed -rn '
s^([a-zA-Z]+) ([a-zA-Z0-9?&+*/.-]+) HTTP/([0-9]+\.[0-9]+)\r$\
Request_Line="&"\
Method="\1"\
Request_URI="\2"\
HTTP_Version="\3"\
p;t;i\
Request_Line= # invalid request
')"
#echo "Request-Line: $Request_Line" >&2
# cat>&2<<EOF
# Request_Line='$Request_Line'
# Method='$Method'
# Request_URI='$Request_URI'
# HTTP_Version='$HTTP_Version'
# EOF
## debug
cat>&2<<EOF
[1;33m$Method[m [1;4;34m$Request_URI[m HTTP/$HTTP_Version
EOF
## }}}
## Parse HTTP-Headers. {{{
# TODO support https://tools.ietf.org/html/rfc7230#section-3.2.4, obs-fold?
# TODO allow headers to appear multiple times
k=
v=
while read -r line; do
line=${line%
}
case $line in
'')
break
;;
[A-Za-z][0-9A-Za-z-]*:*)
k=${line%%:*}
k=${k//-/_}
k=${k,,}
k=req_$k
v=${line#*: }
v=${v## }
printf '[35m%s=[1m%s[m\n' "$k" "$v" >&2
export "$k=$v"
;;
esac
done
unset k v
echo >&2
## }}}
find_item() {
if test ${#1} -ge 7; then
set -- "$(find "$STATEDIR/items" -type f -mindepth 1 -maxdepth 1 \
-regex "$STATEDIR/items/$1[0-9A-Za-z]*$")"
if test $(printf '%s' "$1" | wc -l) = 1; then
echo "$1"
return 0
fi
fi
return 1
}
# run server: STATEDIR=/tmp/htgen-state HTGEN_PORT=1080 ./htgen --serve
# paste: echo lol | curl http://localhost:1080 -d @-
case "$Method $Request_URI" in
"GET /"[0-9a-z]*)
if item=$(find_item ${Request_URI:1}); then
printf 'HTTP/1.1 200 OK\r\n'
printf 'Content-Type: %s\r\n' "$(file -ib $item)"
printf 'Server: %s\r\n' "$Server"
printf 'Connection: close\r\n'
printf 'Content-Length: %d\r\n' $(wc -c < $item)
printf '\r\n'
cat $item
exit
fi
;;
"POST /")
content=$(mktemp -t htgen.$$.content.XXXXXXXX)
trap "rm $content >&2" EXIT
case ${req_expect-} in 100-continue)
printf 'HTTP/1.1 100 Continue\r\n\r\n'
esac
head -c $req_content_length > $content
sha256=$(sha256sum -b $content | cut -d\ -f1)
base32=$(nix-hash --to-base32 --type sha256 $sha256)
item=$STATEDIR/items/$base32
ref=http://$req_host/$base32
if ! test -e $item; then
mkdir -v -p $STATEDIR/items >&2
cp -v $content $item >&2
fi
if item=$(find_item ${base32:0:7}); then
ref=$(echo "$ref"; echo "http://$req_host/${base32:0:7}")
fi
printf 'HTTP/1.1 200 OK\r\n'
printf 'Content-Type: text/plain; charset=UTF-8\r\n'
printf 'Server: %s\r\n' "$Server"
printf 'Connection: close\r\n'
printf 'Content-Length: %d\r\n' $(expr ${#ref} + 1)
printf '\r\n'
printf '%s\n' "$ref"
exit
;;
esac
reply_404
exit
|