*src = p;
return HPACK_ERROR_NONE;
}
+
+static const http3_error_t hpack_error_to_http3_error[] = {
+ [HPACK_ERROR_NONE] = HTTP3_ERROR_NO_ERROR,
+ [HPACK_ERROR_COMPRESSION] = HTTP3_ERROR_QPACK_DECOMPRESSION_FAILED,
+ [HPACK_ERROR_PROTOCOL] = HTTP3_ERROR_GENERAL_PROTOCOL_ERROR,
+ [HPACK_ERROR_UNKNOWN] = HTTP3_ERROR_INTERNAL_ERROR,
+};
+
+static inline hpack_error_t
+qpack_parse_headers_prefix (u8 **src, u8 *end, qpack_decoder_ctx_t *ctx)
+{
+ u8 *p;
+
+ ASSERT (*src < end);
+ p = *src;
+
+ ctx->req_insert_count = hpack_decode_int (&p, end, 8);
+ if (ctx->req_insert_count == HPACK_INVALID_INT || p == end)
+ return HPACK_ERROR_COMPRESSION;
+
+ ctx->delta_base_sign = *p & 0x80;
+ ctx->delta_base = hpack_decode_int (&p, end, 7);
+ if (ctx->req_insert_count == HPACK_INVALID_INT)
+ return HPACK_ERROR_COMPRESSION;
+
+ *src = p;
+ return HPACK_ERROR_NONE;
+}
+
+__clib_export http3_error_t
+qpack_parse_request (u8 *src, u32 src_len, u8 *dst, u32 dst_len,
+ hpack_request_control_data_t *control_data,
+ http_field_line_t **headers,
+ qpack_decoder_ctx_t *decoder_ctx)
+{
+ hpack_error_t rv;
+ u8 *p, *end;
+
+ if (src_len < 3)
+ return HTTP3_ERROR_QPACK_DECOMPRESSION_FAILED;
+
+ p = src;
+ end = src + src_len;
+
+ /* encoded field section prefix */
+ rv = qpack_parse_headers_prefix (&p, end, decoder_ctx);
+ if (rv || p == end)
+ return hpack_error_to_http3_error[rv];
+
+ rv = hpack_decode_request (p, end, dst, dst_len, control_data, headers,
+ decoder_ctx, (void *) qpack_decode_header);
+ return hpack_error_to_http3_error[rv];
+}
+
+__clib_export http3_error_t
+qpack_parse_response (u8 *src, u32 src_len, u8 *dst, u32 dst_len,
+ hpack_response_control_data_t *control_data,
+ http_field_line_t **headers,
+ qpack_decoder_ctx_t *decoder_ctx)
+{
+ hpack_error_t rv;
+ u8 *p, *end;
+
+ if (src_len < 3)
+ return HTTP3_ERROR_QPACK_DECOMPRESSION_FAILED;
+
+ p = src;
+ end = src + src_len;
+
+ /* encoded field section prefix */
+ rv = qpack_parse_headers_prefix (&p, end, decoder_ctx);
+ if (rv || p == end)
+ return hpack_error_to_http3_error[rv];
+
+ rv = hpack_decode_response (p, end, dst, dst_len, control_data, headers,
+ decoder_ctx, qpack_decode_header);
+ return hpack_error_to_http3_error[rv];
+}
#ifndef SRC_PLUGINS_HTTP_QPACK_H_
#define SRC_PLUGINS_HTTP_QPACK_H_
-#include <http/http3/http3.h>
#include <http/http.h>
+#include <http/http2/hpack.h>
+#include <http/http3/http3.h>
+
+typedef struct
+{
+ uword req_insert_count;
+ uword delta_base;
+ u8 delta_base_sign;
+} qpack_decoder_ctx_t;
+
+/**
+ * Request parser
+ *
+ * @param src Header block to parse
+ * @param src_len Length of header block
+ * @param dst Buffer where headers will be decoded
+ * @param dst_len Length of buffer for decoded headers
+ * @param control_data Preparsed pseudo-headers
+ * @param headers List of regular headers
+ * @param decoder_ctx Decoder context
+ *
+ * @return @c HTTP3_ERROR_NO_ERROR on success
+ */
+http3_error_t qpack_parse_request (u8 *src, u32 src_len, u8 *dst, u32 dst_len,
+ hpack_request_control_data_t *control_data,
+ http_field_line_t **headers,
+ qpack_decoder_ctx_t *decoder_ctx);
+
+/**
+ * Response parser
+ *
+ * @param src Header block to parse
+ * @param src_len Length of header block
+ * @param dst Buffer where headers will be decoded
+ * @param dst_len Length of buffer for decoded headers
+ * @param control_data Preparsed pseudo-headers
+ * @param headers List of regular headers
+ * @param decoder_ctx Decoder context
+ *
+ * @return @c HTTP3_ERROR_NO_ERROR on success
+ */
+http3_error_t
+qpack_parse_response (u8 *src, u32 src_len, u8 *dst, u32 dst_len,
+ hpack_response_control_data_t *control_data,
+ http_field_line_t **headers,
+ qpack_decoder_ctx_t *decoder_ctx);
#endif /* SRC_PLUGINS_HTTP_QPACK_H_ */
/* literal field line with literal name */
TEST ("\x23\x61\x62\x63\x01\x5A", "abc", "Z");
+ vlib_cli_output (vm, "qpack_parse_request");
+
+ static http3_error_t (*_qpack_parse_request) (
+ u8 * src, u32 src_len, u8 * dst, u32 dst_len,
+ hpack_request_control_data_t * control_data, http_field_line_t * *headers,
+ qpack_decoder_ctx_t * decoder_ctx);
+
+ _qpack_parse_request =
+ vlib_get_plugin_symbol ("http_plugin.so", "qpack_parse_request");
+
+ http3_error_t err;
+ http_field_line_t *headers = 0;
+ qpack_decoder_ctx_t decoder_ctx = {};
+ hpack_request_control_data_t req_control_data = {};
+ u8 req[] = { 0x00, 0x00, 0xD1, 0xD7, 0x50, 0x01, 0x61,
+ 0xC1, 0x23, 0x61, 0x62, 0x63, 0x01, 0x5A };
+ u16 parsed_bitmap =
+ HPACK_PSEUDO_HEADER_METHOD_PARSED | HPACK_PSEUDO_HEADER_SCHEME_PARSED |
+ HPACK_PSEUDO_HEADER_PATH_PARSED | HPACK_PSEUDO_HEADER_AUTHORITY_PARSED;
+
+ vec_validate_init_empty (buf, 254, 0);
+ err = _qpack_parse_request (req, 14, buf, vec_len (buf), &req_control_data,
+ &headers, &decoder_ctx);
+ HTTP_TEST (
+ (err == HTTP3_ERROR_NO_ERROR &&
+ req_control_data.parsed_bitmap == parsed_bitmap &&
+ req_control_data.method == HTTP_REQ_GET &&
+ req_control_data.scheme == HTTP_URL_SCHEME_HTTPS &&
+ req_control_data.path_len == 1 && req_control_data.path[0] == '/' &&
+ req_control_data.authority_len == 1 &&
+ req_control_data.authority[0] == 'a' && vec_len (headers) == 1 &&
+ req_control_data.headers_len == 4 && headers[0].name_len == 3 &&
+ headers[0].value_len == 1 &&
+ !memcmp (req_control_data.headers + headers[0].name_offset, "abc", 3) &&
+ !memcmp (req_control_data.headers + headers[0].value_offset, "Z", 1)),
+ "decoder result: %U", format_http3_error, err);
+
+ vec_free (buf);
+ vec_free (headers);
+ memset (&decoder_ctx, 0, sizeof (decoder_ctx));
+
+ vlib_cli_output (vm, "qpack_parse_response");
+
+ static http3_error_t (*_qpack_parse_response) (
+ u8 * src, u32 src_len, u8 * dst, u32 dst_len,
+ hpack_response_control_data_t * control_data, http_field_line_t * *headers,
+ qpack_decoder_ctx_t * decoder_ctx);
+
+ _qpack_parse_response =
+ vlib_get_plugin_symbol ("http_plugin.so", "qpack_parse_response");
+
+ hpack_response_control_data_t resp_control_data = {};
+ u8 resp[] = { 0x00, 0x00, 0xD9 };
+
+ vec_validate_init_empty (buf, 63, 0);
+ err = _qpack_parse_response (resp, 3, buf, vec_len (buf), &resp_control_data,
+ &headers, &decoder_ctx);
+ HTTP_TEST (
+ (err == HTTP3_ERROR_NO_ERROR &&
+ resp_control_data.parsed_bitmap == HPACK_PSEUDO_HEADER_STATUS_PARSED &&
+ resp_control_data.sc == HTTP_STATUS_OK && vec_len (headers) == 0),
+ "decoder result: %U", format_http3_error, err);
+ vec_free (buf);
+ vec_free (headers);
+
return 0;
}