]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: qpack: support header litteral name decoding
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 14 Jun 2022 14:34:55 +0000 (16:34 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 15 Jun 2022 12:54:51 +0000 (14:54 +0200)
Complete QPACK decoding with full implementation of litteral field name
with litteral value representation. This change is mandatory to support
decoding of headers name not present in the QPACK static table.
Previously, these headers were silently ignored and not transferred on
the backend request.

QPACK decoding should now be sufficient to deal with all real
situations. Only post-base indices representation are not handled but
this should not cause a problem as they are only used for the dynamic
table whose size is null as announced by the haproxy implementation.

The direct impact of this change is that it should now be possible to
use complex webapp through a QUIC frontend.

This must be backported up to 2.6.

src/qpack-dec.c

index f5ba5514465b2225af454ed09780120bcc7c3865..5546590bbaf82a73cb9def35ea34bfc12710aca5 100644 (file)
@@ -345,7 +345,7 @@ int qpack_decode_fs(const unsigned char *raw, size_t len, struct buffer *tmp,
                }
                else if (efl_type & QPACK_LFL_WLN_BIT) {
                        /* Literal field line with literal name */
-                       unsigned int n __maybe_unused, hname __maybe_unused, hvalue __maybe_unused;
+                       unsigned int n __maybe_unused, hname, hvalue;
                        uint64_t name_len, value_len;
 
                        qpack_debug_printf(stderr, "Literal field line with literal name:");
@@ -367,6 +367,32 @@ int qpack_decode_fs(const unsigned char *raw, size_t len, struct buffer *tmp,
                                goto out;
                        }
 
+                       if (hname) {
+                               char *trash;
+                               int nlen;
+
+                               trash = chunk_newstr(tmp);
+                               if (!trash) {
+                                       qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
+                                       ret = -QPACK_DECOMPRESSION_FAILED;
+                                       goto out;
+                               }
+                               nlen = huff_dec(raw, name_len, trash, tmp->size - tmp->data);
+                               if (nlen == (uint32_t)-1) {
+                                       qpack_debug_printf(stderr, " can't decode huffman.\n");
+                                       ret = -QPACK_ERR_HUFFMAN;
+                                       goto out;
+                               }
+
+                               qpack_debug_printf(stderr, " [name huff %d->%d '%s']", (int)name_len, (int)nlen, trash);
+                               /* makes an ist from tmp storage */
+                               b_add(tmp, nlen);
+                               list[hdr_idx].n = ist2(trash, nlen);
+                       }
+                       else {
+                               list[hdr_idx].n = ist2(raw, name_len);
+                       }
+
                        raw += name_len;
                        len -= name_len;
                        hvalue = *raw & 0x80;
@@ -385,9 +411,36 @@ int qpack_decode_fs(const unsigned char *raw, size_t len, struct buffer *tmp,
                                goto out;
                        }
 
-                       /* XXX Value string XXX */
+                       if (hvalue) {
+                               char *trash;
+                               int nlen;
+
+                               trash = chunk_newstr(tmp);
+                               if (!trash) {
+                                       qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
+                                       ret = -QPACK_DECOMPRESSION_FAILED;
+                                       goto out;
+                               }
+                               nlen = huff_dec(raw, value_len, trash, tmp->size - tmp->data);
+                               if (nlen == (uint32_t)-1) {
+                                       qpack_debug_printf(stderr, " can't decode huffman.\n");
+                                       ret = -QPACK_ERR_HUFFMAN;
+                                       goto out;
+                               }
+
+                               qpack_debug_printf(stderr, " [name huff %d->%d '%s']", (int)value_len, (int)nlen, trash);
+                               /* makes an ist from tmp storage */
+                               b_add(tmp, nlen);
+                               list[hdr_idx].v = ist2(trash, nlen);
+                       }
+                       else {
+                               list[hdr_idx].v = ist2(raw, value_len);
+                       }
+
                        raw += value_len;
                        len -= value_len;
+
+                       ++hdr_idx;
                }
                qpack_debug_printf(stderr, "\n");
        }