mirror of
				https://git.haproxy.org/git/haproxy.git/
				synced 2025-11-04 10:31:14 +01:00 
			
		
		
		
	Implement a standalone binary to be able to easily a hex-string QPACK stream. The binary must be compiled via the Makefile. Hex-strings are specified on stdin.
		
			
				
	
	
		
			172 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QPACK stream decoder. Decode a series of hex codes on stdin using one line
 | 
						|
 * per H3 HEADERS frame. Silently skip spaces, tabs, CR, '-' and ','.
 | 
						|
 *
 | 
						|
 * Compilation via Makefile
 | 
						|
 *
 | 
						|
 * Example run:
 | 
						|
 *   echo 0000d1d7508b089d5c0b8170dc101a699fc15f5085ed6989397f | ./dev/qpack/decode
 | 
						|
 */
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
#include <inttypes.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#define MAX_RQ_SIZE 65536
 | 
						|
#define MAX_HDR_NUM 1000
 | 
						|
 | 
						|
#define QPACK_STANDALONE
 | 
						|
 | 
						|
#define USE_OPENSSL
 | 
						|
#define USE_QUIC
 | 
						|
 | 
						|
#include <haproxy/buf-t.h>
 | 
						|
#include <haproxy/http-hdr-t.h>
 | 
						|
#include <haproxy/qpack-dec.h>
 | 
						|
#include <haproxy/qpack-tbl.h>
 | 
						|
 | 
						|
char line[MAX_RQ_SIZE * 3 + 3];
 | 
						|
uint8_t bin[MAX_RQ_SIZE];
 | 
						|
 | 
						|
char tmp_buf[MAX_RQ_SIZE];
 | 
						|
struct buffer buf   = { .area = tmp_buf,   .data = 0, .size = sizeof(tmp_buf)   };
 | 
						|
 | 
						|
#define DEBUG_QPACK
 | 
						|
#include "../src/hpack-huff.c"
 | 
						|
#include "../src/qpack-dec.c"
 | 
						|
#include "../src/qpack-tbl.c"
 | 
						|
 | 
						|
/* define to compile with BUG_ON/ABORT_NOW statements */
 | 
						|
void ha_backtrace_to_stderr(void)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
/* taken from dev/hpack/decode.c */
 | 
						|
int hex2bin(const char *hex, uint8_t *bin, int size)
 | 
						|
{
 | 
						|
	int a, b, c;
 | 
						|
	uint8_t code;
 | 
						|
	int len = 0;
 | 
						|
 | 
						|
	a = b = -1;
 | 
						|
 | 
						|
	for (; *hex; hex++) {
 | 
						|
		c = *hex;
 | 
						|
		if (c == ' ' || c == '\t' || c == '\r' ||
 | 
						|
		    c == '-' || c == ',')
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (c == '\n' || c == '#')
 | 
						|
			break;
 | 
						|
 | 
						|
		if (c >= '0' && c <= '9')
 | 
						|
			c -= '0';
 | 
						|
		else if (c >= 'a' && c <= 'f')
 | 
						|
			c -= 'a' - 10;
 | 
						|
		else if (c >= 'A' && c <= 'F')
 | 
						|
			c -= 'A' - 10;
 | 
						|
		else
 | 
						|
			return -1;
 | 
						|
 | 
						|
		if (a == -1)
 | 
						|
			a = c;
 | 
						|
		else
 | 
						|
			b = c;
 | 
						|
 | 
						|
		if (b == -1)
 | 
						|
			continue;
 | 
						|
 | 
						|
		code = (a << 4) | b;
 | 
						|
		a = b = -1;
 | 
						|
		if (len >= size)
 | 
						|
			return -2;
 | 
						|
 | 
						|
		bin[len] = code;
 | 
						|
		len++;
 | 
						|
	}
 | 
						|
	if (a >= 0 || b >= 0)
 | 
						|
		return -3;
 | 
						|
	return len;
 | 
						|
}
 | 
						|
 | 
						|
/* taken from src/tools.c */
 | 
						|
void debug_hexdump(FILE *out, const char *pfx, const char *buf,
 | 
						|
                   unsigned int baseaddr, int len)
 | 
						|
{
 | 
						|
	unsigned int i;
 | 
						|
	int b, j;
 | 
						|
 | 
						|
	for (i = 0; i < (len + (baseaddr & 15)); i += 16) {
 | 
						|
		b = i - (baseaddr & 15);
 | 
						|
		fprintf(out, "%s%08x: ", pfx ? pfx : "", i + (baseaddr & ~15));
 | 
						|
		for (j = 0; j < 8; j++) {
 | 
						|
			if (b + j >= 0 && b + j < len)
 | 
						|
				fprintf(out, "%02x ", (unsigned char)buf[b + j]);
 | 
						|
			else
 | 
						|
				fprintf(out, "   ");
 | 
						|
		}
 | 
						|
 | 
						|
		if (b + j >= 0 && b + j < len)
 | 
						|
			fputc('-', out);
 | 
						|
		else
 | 
						|
			fputc(' ', out);
 | 
						|
 | 
						|
		for (j = 8; j < 16; j++) {
 | 
						|
			if (b + j >= 0 && b + j < len)
 | 
						|
				fprintf(out, " %02x", (unsigned char)buf[b + j]);
 | 
						|
			else
 | 
						|
				fprintf(out, "   ");
 | 
						|
		}
 | 
						|
 | 
						|
		fprintf(out, "   ");
 | 
						|
		for (j = 0; j < 16; j++) {
 | 
						|
			if (b + j >= 0 && b + j < len) {
 | 
						|
				if (isprint((unsigned char)buf[b + j]))
 | 
						|
					fputc((unsigned char)buf[b + j], out);
 | 
						|
				else
 | 
						|
					fputc('.', out);
 | 
						|
			}
 | 
						|
			else
 | 
						|
				fputc(' ', out);
 | 
						|
		}
 | 
						|
		fputc('\n', out);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char **argv)
 | 
						|
{
 | 
						|
	struct http_hdr hdrs[MAX_HDR_NUM];
 | 
						|
	int len, outlen, hdr_idx;
 | 
						|
 | 
						|
	do {
 | 
						|
		if (!fgets(line, sizeof(line), stdin))
 | 
						|
			break;
 | 
						|
 | 
						|
		if ((len = hex2bin(line, bin, MAX_RQ_SIZE)) < 0)
 | 
						|
			break;
 | 
						|
 | 
						|
		outlen = qpack_decode_fs(bin, len, &buf, hdrs,
 | 
						|
		                         sizeof(hdrs) / sizeof(hdrs[0]));
 | 
						|
		if (outlen < 0) {
 | 
						|
			fprintf(stderr, "QPACK decoding failed: %d\n", outlen);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		hdr_idx = 0;
 | 
						|
		fprintf(stderr, "<<< Found %d headers:\n", outlen);
 | 
						|
		while (1) {
 | 
						|
			if (isteq(hdrs[hdr_idx].n, ist("")))
 | 
						|
				break;
 | 
						|
 | 
						|
			fprintf(stderr, "%.*s: %.*s\n",
 | 
						|
			        (int)hdrs[hdr_idx].n.len, hdrs[hdr_idx].n.ptr,
 | 
						|
			        (int)hdrs[hdr_idx].v.len, hdrs[hdr_idx].v.ptr);
 | 
						|
 | 
						|
			++hdr_idx;
 | 
						|
		}
 | 
						|
	} while (1);
 | 
						|
 | 
						|
	return EXIT_SUCCESS;
 | 
						|
}
 |