@@ -479,6 +479,95 @@ TEST(tg_answer) {
479479 error_if (result != expected);
480480}
481481
482+ TEST (tg_answer_parts) {
483+ std::vector<hpack::byte_t > bytes = {
484+ 0x88 , 0x76 , 0x89 , 0xaa , 0x63 , 0x55 , 0xe5 , 0x80 , 0xae , 0x17 , 0x97 , 0x7 , 0x61 , 0x96 , 0xc3 , 0x61 , 0xbe ,
485+ 0x94 , 0x3 , 0x8a , 0x6e , 0x2d , 0x6a , 0x8 , 0x2 , 0x69 , 0x40 , 0x3b , 0x70 , 0xf , 0x5c , 0x13 , 0x4a , 0x62 ,
486+ 0xd1 , 0xbf , 0x5f , 0x8b , 0x1d , 0x75 , 0xd0 , 0x62 , 0xd , 0x26 , 0x3d , 0x4c , 0x74 , 0x41 , 0xea , 0x5c , 0x4 ,
487+ 0x31 , 0x39 , 0x32 , 0x36 , 0x0 , 0x91 , 0x42 , 0x6c , 0x31 , 0x12 , 0xb2 , 0x6c , 0x1d , 0x48 , 0xac , 0xf6 , 0x25 ,
488+ 0x64 , 0x14 , 0x96 , 0xd8 , 0x64 , 0xfa , 0xa0 , 0xa4 , 0x7e , 0x56 , 0x1c , 0xc5 , 0x81 , 0x90 , 0xb6 , 0xcb , 0x80 ,
489+ 0x0 , 0x3e , 0xd4 , 0x35 , 0x44 , 0xa2 , 0xd9 , 0xb , 0xba , 0xd8 , 0xef , 0x9e , 0x91 , 0x9a , 0xa4 , 0x7d , 0xa9 ,
490+ 0x5d , 0x85 , 0xa0 , 0xe3 , 0x93 , 0x0 , 0x93 , 0x19 , 0x8 , 0x54 , 0x21 , 0x62 , 0x1e , 0xa4 , 0xd8 , 0x7a , 0x16 ,
491+ 0x1d , 0x14 , 0x1f , 0xc2 , 0xc7 , 0xb0 , 0xd3 , 0x1a , 0xaf , 0x1 , 0x2a , 0x0 , 0x94 , 0x19 , 0x8 , 0x54 , 0x21 ,
492+ 0x62 , 0x1e , 0xa4 , 0xd8 , 0x7a , 0x16 , 0x1d , 0x14 , 0x1f , 0xc2 , 0xd4 , 0x95 , 0x33 , 0x9e , 0x44 , 0x7f , 0x90 ,
493+ 0xc5 , 0x83 , 0x7f , 0xd2 , 0x9a , 0xf5 , 0x6e , 0xdf , 0xf4 , 0xa6 , 0xad , 0x7b , 0xf2 , 0x6a , 0xd3 , 0xbb , 0x0 ,
494+ 0x94 , 0x19 , 0x8 , 0x54 , 0x21 , 0x62 , 0x1e , 0xa4 , 0xd8 , 0x7a , 0x16 , 0x2f , 0x9a , 0xce , 0x82 , 0xad , 0x39 ,
495+ 0x47 , 0x21 , 0x6c , 0x47 , 0xa5 , 0xbc , 0x7a , 0x92 , 0x5a , 0x92 , 0xb6 , 0x72 , 0xd5 , 0x32 , 0x67 , 0xfa , 0xbc ,
496+ 0x7a , 0x92 , 0x5a , 0x92 , 0xb6 , 0xff , 0x55 , 0x97 , 0xea , 0xf8 , 0xd2 , 0x5f , 0xad , 0xc5 , 0xb3 , 0xb9 , 0x6c ,
497+ 0xfa , 0xbc , 0x7a , 0xaa , 0x29 , 0x12 , 0x63 , 0xd5 ,
498+ };
499+ hpack::decoder e;
500+ headers_t expected{
501+ {" :status" , " 200" },
502+ {" server" , " nginx/1.18.0" },
503+ {" date" , " Fri, 06 Sep 2024 07:08:24 GMT" },
504+ {" content-type" , " application/json" },
505+ {" content-length" , " 1926" },
506+ {" strict-transport-security" , " max-age=31536000; includeSubDomains; preload" },
507+ {" access-control-allow-origin" , " *" },
508+ {" access-control-allow-methods" , " GET, POST, OPTIONS" },
509+ {" access-control-expose-headers" , " Content-Length,Content-Type,Date,Server,Connection" },
510+ };
511+ headers_t result;
512+ hpack::stream_decoder decoder (e);
513+ std::span<hpack::byte_t > chunks = bytes;
514+ auto vtor = [&](std::string_view name, std::string_view value) {
515+ result.push_back ({std::string (name), std::string (value)});
516+ };
517+
518+ while (!chunks.empty ()) {
519+ decoder.feed (chunks.subspan (0 , 1 ), chunks.size () == 1 , vtor);
520+ chunks = chunks.subspan (1 );
521+ }
522+ error_if (result != expected);
523+ }
524+
525+ TEST (stream_decoder) {
526+ headers_t expected{
527+ {" :status" , " 200" },
528+ {" server" , " nginx/1.18.0" },
529+ {" longstr" , std::string (15000 , ' A' )},
530+ {" content-type" , " application/json" },
531+ {" content-length" , " 1926" },
532+ {" strict-transport-security" , " max-age=31536000; includeSubDomains; preload" },
533+ {" access-control-allow-origin" , " *" },
534+ {" access-control-allow-methods" , " GET, POST, OPTIONS" },
535+ {" access-control-expose-headers" , " Content-Length,Content-Type,Date,Server,Connection" },
536+ {std::string (15000 , ' B' ), std::string (15000 , ' A' )},
537+ };
538+ std::mt19937 g (146 );
539+ using dist = std::uniform_int_distribution<>;
540+ bytes_t bytes;
541+ hpack::encoder enc;
542+ // encode twice for using indexes
543+ auto copy = expected;
544+ expected.insert (expected.end (), copy.begin (), copy.end ());
545+ for (auto & [n, v] : expected) {
546+ enc.encode (n, v, std::back_inserter (bytes));
547+ }
548+ hpack::decoder dec;
549+
550+ headers_t result;
551+ hpack::stream_decoder decoder (dec);
552+
553+ auto vtor = [&](std::string_view name, std::string_view value) {
554+ result.push_back ({std::string (name), std::string (value)});
555+ };
556+ std::span<hpack::byte_t > chunks;
557+ for (int i = 0 ; i < 100 ; ++i) {
558+ chunks = bytes;
559+ result.clear ();
560+ // `decoder` must be empty after each last_chunk decoder.clear();
561+ while (!chunks.empty ()) {
562+ auto sz = dist (0 , chunks.size ())(g);
563+ decoder.feed (chunks.subspan (0 , sz), chunks.size () == sz, vtor);
564+ chunks = chunks.subspan (sz);
565+ }
566+ g.discard (10 );
567+ error_if (result != expected);
568+ }
569+ }
570+
482571TEST (decode_status) {
483572 hpack::encoder e;
484573 hpack::decoder de;
@@ -1013,6 +1102,8 @@ TEST(encode_with_cache) {
10131102}
10141103
10151104int main () {
1105+ test_stream_decoder ();
1106+ test_tg_answer_parts ();
10161107 test_dyntable_move ();
10171108 test_encode_status ();
10181109 test_encode_with_cache ();
0 commit comments