summaryrefslogtreecommitdiffstats
path: root/htgen
blob: 314ed52bc4b0d46a6f2dc70c43de9451e526d46a (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
#! /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
$Method $Request_URI 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 '%s=%s\n' "$k" "$v" >&2
      export "$k=$v"
      ;;
  esac
done
unset k v

echo >&2
## }}}

# 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]*)
      item=$STATEDIR/items$Request_URI
      if test -e $item; 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

    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