summaryrefslogtreecommitdiffstats
path: root/htgen
blob: 52d32e56b34c629af3140a6a5a48a787d7a50a19 (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
#! /bin/sh
# vim:set fdm=marker:
set -euf

Server=htgen

## parse arguments {{{
action=handle_request
verbose=${HTGEN_VERBOSE-false}
while test $# -gt 0; do
  case $1 in
    --serve) action=serve; shift; continue;;
    --verbose) verbose=true; shift; continue;;
    *) echo "$0: error: bad argument: $1" >&2; exit 1;;
  esac
done
## }}}
## dispatch on $action {{
case $action in
  handle_request)
    : # fall through for handling the request
    ;;
  serve)
    HTGEN_HOST=${HTGEN_HOST-0.0.0.0}
    HTGEN_PORT=${HTGEN_PORT-42380}
    HTGEN_SCRIPT=${HTGEN_SCRIPT-:}; export HTGEN_SCRIPT
    HTGEN_SCRIPT_FILE=${HTGEN_SCRIPT_FILE-/dev/null}; export HTGEN_SCRIPT_FILE
    HTGEN_VERBOSE=$verbose; export HTGEN_VERBOSE
    TCPSERVER_OPTS='-c 423 -t 2 -D'
    if test "$HTGEN_VERBOSE" = true; then
      echo "#### $Server $HTGEN_HOST:$HTGEN_PORT" >&2
    fi
    exec tcpserver $TCPSERVER_OPTS "$HTGEN_HOST" "$HTGEN_PORT" "$0"
    ;;
  *)
    echo "$0: error: bad action: $action" >&2
    exit 2
    ;;
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 '+%Y-%m-%d %H:%M:%S')
if test "$HTGEN_VERBOSE" = true; then
  cat 1>&2 <<EOF

# ${TCPREMOTEHOST-}[$TCPREMOTEIP]:$TCPREMOTEPORT connected at $date over $PROTO
EOF
fi
## }}}
## Parse Request-Line. {{{
eval "$(
  read -r Request_Line
  jq --arg Request_Line "$Request_Line" -nRr '
    $Request_Line |
    sub("\\r?$";"") |
    match(
      "^(?<Method>[A-Za-z]+)" +
      " (?<Request_URI>[A-Za-z0-9%&()*+./:=?@_-]+)" +
      " HTTP/(?<HTTP_Version>[0-9]+\\.[0-9]+)" +
      "$"
    )
    .captures |
    map("\(.name)=\(@sh "\(.string)")") |
    join("\n")
  '
)"

## debug
if test "$HTGEN_VERBOSE" = true; then
  cat 1>&2 <<EOF
$Method $Request_URI HTTP/$HTTP_Version
EOF
fi
## }}}
## 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=$(echo "$k" | tr [:upper:]- [:lower:]_)
      k=req_$k
      v=${line#*:}
      v=${v## }
      if test "$HTGEN_VERBOSE" = true; then
        printf '%s=%s\n' "$k" "$v" >&2
      fi
      export "$k=$v"
      ;;
  esac
done
unset k v

if test "$HTGEN_VERBOSE" = true; then
  echo >&2
fi
## }}}

eval "$HTGEN_SCRIPT"
. "$HTGEN_SCRIPT_FILE"

reply_404