blob: 4d129fa40fe3f43a2552c4f3cf1c4761ce7b2ac4 [file] [log] [blame]
Willy Tarreau78bb9342023-04-26 09:40:23 +02001#!/usr/bin/env bash
2
3# Usage: mkhdr -l <len> -t <type> -f <flags> -sid <sid> > hdr.bin
4# All fields are optional. 0 assumed when absent.
5
6USAGE=\
Willy Tarreaue8ae99b2023-04-26 11:25:46 +02007"Usage: %s [-l <len> ] [-t <type>] [-f <flags>] [-i <sid>] [ -d <data> ] > hdr.bin
8 Numbers are decimal or 0xhex. Not set=0. If <data> is passed, it points
9 to a file that is read and chunked into frames of <len> bytes.
Willy Tarreau78bb9342023-04-26 09:40:23 +020010
11Supported symbolic types (case insensitive prefix match):
12 DATA (0x00) PUSH_PROMISE (0x05)
13 HEADERS (0x01) PING (0x06)
14 PRIORITY (0x02) GOAWAY (0x07)
15 RST_STREAM (0x03) WINDOW_UPDATE (0x08)
16 SETTINGS (0x04) CONTINUATION (0x09)
17
18Supported symbolic flags (case insensitive prefix match):
19 ES (0x01) PAD (0x08)
20 EH (0x04) PRIO (0x20)
21
22"
23
24LEN=
25TYPE=
26FLAGS=
27ID=
28
29die() {
30 [ "$#" -eq 0 ] || echo "$*" >&2
31 exit 1
32}
33
34quit() {
35 [ "$#" -eq 0 ] || echo "$*"
36 exit 0
37}
38
39# print usage with $1 as the cmd name
40usage() {
41 printf "$USAGE" "$1";
42}
43
44# Send frame made of $1 $2 $3 $4 to stdout.
45# Usage: mkframe <len> <type> <flags> <id>
46mkframe() {
47 local L="${1:-0}"
48 local T="${2:-0}"
49 local F="${3:-0}"
50 local I="${4:-0}"
51 local t f
52
53 # get the first match in this order
54 for t in DATA:0x00 HEADERS:0x01 RST_STREAM:0x03 SETTINGS:0x04 PING:0x06 \
55 GOAWAY:0x07 WINDOW_UPDATE:0x08 CONTINUATION:0x09 PRIORITY:0x02 \
56 PUSH_PROMISE:0x05; do
57 if [ -z "${t##${T^^*}*}" ]; then
58 T="${t##*:}"
59 break
60 fi
61 done
62
63 if [ -n "${T##[0-9]*}" ]; then
64 echo "Unknown type '$T'" >&2
65 usage "${0##*}"
66 die
67 fi
68
69 # get the first match in this order
70 for f in ES:0x01 EH:0x04 PAD:0x08 PRIO:0x20; do
71 if [ -z "${f##${F^^*}*}" ]; then
72 F="${f##*:}"
73 fi
74 done
75
76 if [ -n "${F##[0-9]*}" ]; then
77 echo "Unknown type '$T'" >&2
78 usage "${0##*}"
79 die
80 fi
81
82 L=$(( L )); T=$(( T )); F=$(( F )); I=$(( I ))
83
84 L0=$(( (L >> 16) & 255 )); L0=$(printf "%02x" $L0)
85 L1=$(( (L >> 8) & 255 )); L1=$(printf "%02x" $L1)
86 L2=$(( (L >> 0) & 255 )); L2=$(printf "%02x" $L2)
87
88 T0=$(( (T >> 0) & 255 )); T0=$(printf "%02x" $T0)
89 F0=$(( (F >> 0) & 255 )); F0=$(printf "%02x" $F0)
90
91 I0=$(( (I >> 24) & 127 )); I0=$(printf "%02x" $I0)
92 I1=$(( (I >> 16) & 255 )); I1=$(printf "%02x" $I1)
93 I2=$(( (I >> 8) & 255 )); I2=$(printf "%02x" $I2)
94 I3=$(( (I >> 0) & 255 )); I3=$(printf "%02x" $I3)
95
96 printf "\x$L0\x$L1\x$L2\x$T0\x$F0\x$I0\x$I1\x$I2\x$I3"
97}
98
99## main
100
101if [ $# -le 1 ]; then
102 usage "${0##*}"
103 die
104fi
105
106while [ -n "$1" -a -z "${1##-*}" ]; do
107 case "$1" in
108 -l) LEN="$2" ; shift 2 ;;
109 -t) TYPE="$2" ; shift 2 ;;
110 -f) FLAGS="$2" ; shift 2 ;;
111 -i) ID="$2" ; shift 2 ;;
Willy Tarreaue8ae99b2023-04-26 11:25:46 +0200112 -d) DATA="$2" ; shift 2 ;;
Willy Tarreau78bb9342023-04-26 09:40:23 +0200113 -h|--help) usage "${0##*}"; quit;;
114 *) usage "${0##*}"; die ;;
115 esac
116done
117
118if [ $# -gt 0 ]; then
119 usage "${0##*}"
120 die
121fi
122
123# default values for LEN and ID
124LEN=${LEN:-0};
125if [ -n "${LEN##[0-9]*}" ]; then
126 echo "Unparsable length '$LEN'" >&2
127 usage "${0##*}"
128 die
129fi
130
131ID=${ID:-0};
132if [ -n "${ID##[0-9]*}" ]; then
133 echo "Unparsable stream ID '$ID'" >&2
134 usage "${0##*}"
135 die
136fi
137
Willy Tarreaue8ae99b2023-04-26 11:25:46 +0200138if [ -z "$DATA" ]; then
139 mkframe "$LEN" "$TYPE" "$FLAGS" "$ID"
140else
141 # read file $DATA in <LEN> chunks and send it in multiple frames
142 # advertising their respective lengths.
143 [ $LEN -gt 0 ] || LEN=16384
144
145 while read -rN "$LEN" payload || [ ${#payload} -gt 0 ]; do
146 mkframe "${#payload}" "$TYPE" "$FLAGS" "$ID"
147 echo -n "$payload"
148 done < "$DATA"
149fi
Willy Tarreau78bb9342023-04-26 09:40:23 +0200150
151exit 0