diff options
Diffstat (limited to 'dev/h2/mkhdr.sh')
-rwxr-xr-x | dev/h2/mkhdr.sh | 80 |
1 files changed, 68 insertions, 12 deletions
diff --git a/dev/h2/mkhdr.sh b/dev/h2/mkhdr.sh index 4d129fa..4ed1a07 100755 --- a/dev/h2/mkhdr.sh +++ b/dev/h2/mkhdr.sh @@ -4,9 +4,13 @@ # All fields are optional. 0 assumed when absent. USAGE=\ -"Usage: %s [-l <len> ] [-t <type>] [-f <flags>] [-i <sid>] [ -d <data> ] > hdr.bin +"Usage: %s [-l <len> ] [-t <type>] [-f <flags>[,...]] [-i <sid>] [ -d <data> ] + [ -e <name> <value> ]* [ -r|-R raw ] [ -h | --help ] > hdr.bin Numbers are decimal or 0xhex. Not set=0. If <data> is passed, it points - to a file that is read and chunked into frames of <len> bytes. + to a file that is read and chunked into frames of <len> bytes. -e + encodes a headers frame (by default) with all headers at once encoded + in literal. Use type 'p' for the preface. Use -r to pass raw data or + -R to pass raw hex codes (hex digit pairs, blanks ignored). Supported symbolic types (case insensitive prefix match): DATA (0x00) PUSH_PROMISE (0x05) @@ -25,6 +29,8 @@ LEN= TYPE= FLAGS= ID= +RAW= +HDR=( ) die() { [ "$#" -eq 0 ] || echo "$*" >&2 @@ -48,7 +54,7 @@ mkframe() { local T="${2:-0}" local F="${3:-0}" local I="${4:-0}" - local t f + local t f f2 f3 # get the first match in this order for t in DATA:0x00 HEADERS:0x01 RST_STREAM:0x03 SETTINGS:0x04 PING:0x06 \ @@ -66,17 +72,37 @@ mkframe() { die fi - # get the first match in this order - for f in ES:0x01 EH:0x04 PAD:0x08 PRIO:0x20; do - if [ -z "${f##${F^^*}*}" ]; then - F="${f##*:}" + # get the first match in this order, for each entry delimited by ','. + # E.g.: "-f ES,EH" + f2=${F^^*}; F=0 + + while [ -n "$f2" ]; do + f3="${f2%%,*}" + tmp="" + for f in ES:0x01 EH:0x04 PAD:0x08 PRIO:0x20; do + if [ -n "$f3" -a -z "${f##${f3}*}" ]; then + tmp="${f#*:}" + break + fi + done + + if [ -n "$tmp" ]; then + F=$(( F | tmp )) + f2="${f2#$f3}" + f2="${f2#,}" + elif [ -z "${f3##[X0-9A-F]*}" ]; then + F=$(( F | f3 )) + f2="${f2#$f3}" + f2="${f2#,}" + else + echo "Unknown flag(s) '$f3'" >&2 + usage "${0##*}" + die fi done - if [ -n "${F##[0-9]*}" ]; then - echo "Unknown type '$T'" >&2 - usage "${0##*}" - die + if [ -n "$f2" ]; then + F="${f2} | ${F}" fi L=$(( L )); T=$(( T )); F=$(( F )); I=$(( I )) @@ -110,6 +136,9 @@ while [ -n "$1" -a -z "${1##-*}" ]; do -f) FLAGS="$2" ; shift 2 ;; -i) ID="$2" ; shift 2 ;; -d) DATA="$2" ; shift 2 ;; + -r) RAW="$2" ; shift 2 ;; + -R) RAW="$(printf $(echo -n "${2// /}" | sed -e 's/\([^ ][^ ]\)/\\\\x\1/g'))" ; shift 2 ;; + -e) TYPE=1; HDR[${#HDR[@]}]="$2=$3"; shift 3 ;; -h|--help) usage "${0##*}"; quit;; *) usage "${0##*}"; die ;; esac @@ -135,8 +164,35 @@ if [ -n "${ID##[0-9]*}" ]; then die fi -if [ -z "$DATA" ]; then +if [ "$TYPE" = "p" ]; then + printf "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +elif [ -z "$DATA" ]; then + # If we're trying to emit literal headers, let's pre-build the raw data + # and measure their total length. + if [ ${#HDR[@]} -gt 0 ]; then + # limited to 127 bytes for name and value + for h in "${HDR[@]}"; do + n=${h%%=*} + v=${h#*=} + nl=${#n} + vl=${#v} + nl7=$(printf "%02x" $((nl & 127))) + vl7=$(printf "%02x" $((vl & 127))) + RAW="${RAW}\x40\x${nl7}${n}\x${vl7}${v}" + done + fi + + # compute length if RAW set + if [ -n "$RAW" ]; then + LEN=$(printf "${RAW}" | wc -c) + fi + mkframe "$LEN" "$TYPE" "$FLAGS" "$ID" + + # now emit the literal data of advertised length + if [ -n "$RAW" ]; then + printf "${RAW}" + fi else # read file $DATA in <LEN> chunks and send it in multiple frames # advertising their respective lengths. |