1 /*
2 restinio
3 */
4
5 #include <catch2/catch.hpp>
6
7 #include <restinio/helpers/easy_parser.hpp>
8 #include <restinio/helpers/http_field_parsers/cache-control.hpp>
9 #include <restinio/helpers/http_field_parsers/media-type.hpp>
10 #include <restinio/helpers/http_field_parsers/content-type.hpp>
11 #include <restinio/helpers/http_field_parsers/content-encoding.hpp>
12 #include <restinio/helpers/http_field_parsers/accept.hpp>
13 #include <restinio/helpers/http_field_parsers/content-disposition.hpp>
14
15 struct media_type_t
16 {
17 std::string m_type;
18 std::string m_subtype;
19 };
20
21 bool
operator ==(const media_type_t & a,const media_type_t & b)22 operator==( const media_type_t & a, const media_type_t & b ) noexcept
23 {
24 return a.m_type == b.m_type && a.m_subtype == b.m_subtype;
25 }
26
27 std::ostream &
operator <<(std::ostream & to,const media_type_t & v)28 operator<<( std::ostream & to, const media_type_t & v )
29 {
30 return (to << v.m_type << '/' << v.m_subtype);
31 }
32
33 struct content_type_t
34 {
35 media_type_t m_media_type;
36 std::map< std::string, std::string > m_parameters;
37 };
38
39 struct value_with_opt_params_t
40 {
41 using param_t = std::pair< std::string, restinio::optional_t<std::string> >;
42 using param_storage_t = std::vector< param_t >;
43
44 std::string m_value;
45 param_storage_t m_params;
46 };
47
48 TEST_CASE( "token", "[token]" )
49 {
50 using namespace restinio::http_field_parsers;
51
__anond34307e20102( restinio::string_view_t what ) 52 const auto try_parse = []( restinio::string_view_t what ) {
53 return restinio::easy_parser::try_parse( what, token_p() );
54 };
55
56 {
57 const auto result = try_parse( "" );
58
59 REQUIRE( !result.first );
60 }
61
62 {
63 const auto result = try_parse( "," );
64
65 REQUIRE( !result.first );
66 }
67
68 {
69 const auto result = try_parse( " multipart" );
70
71 REQUIRE( !result.first );
72 }
73
74 {
75 const auto result = try_parse( "multipart" );
76
77 REQUIRE( result.first );
78 REQUIRE( "multipart" == result.second );
79 }
80 }
81
82 TEST_CASE( "alternatives", "[token][alternatives]" )
83 {
84 using namespace restinio::http_field_parsers;
85
__anond34307e20202( restinio::string_view_t what ) 86 const auto try_parse = []( restinio::string_view_t what ) {
87 return restinio::easy_parser::try_parse( what,
88 produce< std::string >(
89 alternatives(
90 symbol(','),
91 token_p() >> to_lower() >> as_result() )
92 )
93 );
94 };
95
96 {
97 const auto result = try_parse( "," );
98
99 REQUIRE( result.first );
100 REQUIRE( result.second.empty() );
101 }
102
103 {
104 const auto result = try_parse( "multipart" );
105
106 REQUIRE( result.first );
107 REQUIRE( "multipart" == result.second );
108 }
109
110 {
111 const auto result = try_parse( "MultiPart" );
112
113 REQUIRE( result.first );
114 REQUIRE( "multipart" == result.second );
115 }
116 }
117
118 TEST_CASE( "maybe", "[token][maybe]" )
119 {
120 using namespace restinio::http_field_parsers;
121
122 using result_t = std::pair< std::string, std::string >;
123
__anond34307e20302( restinio::string_view_t what ) 124 const auto try_parse = []( restinio::string_view_t what ) {
125 return restinio::easy_parser::try_parse( what,
126 produce< result_t >(
127 token_p() >> &result_t::first,
128 maybe(
129 symbol('/'),
130 token_p() >> &result_t::second
131 )
132 )
133 );
134 };
135
136 {
137 const auto result = try_parse( "text" );
138
139 REQUIRE( result.first );
140 REQUIRE( "text" == result.second.first );
141 REQUIRE( result.second.second.empty() );
142 }
143
144 {
145 const auto result = try_parse( "text/*" );
146
147 REQUIRE( result.first );
148 REQUIRE( "text" == result.second.first );
149 REQUIRE( "*" == result.second.second );
150 }
151 }
152
153 TEST_CASE( "sequence", "[token][sequence]" )
154 {
155 using namespace restinio::http_field_parsers;
156
157 using result_t = std::pair< std::string, std::string >;
158
__anond34307e20402( restinio::string_view_t what ) 159 const auto try_parse = []( restinio::string_view_t what ) {
160 return restinio::easy_parser::try_parse( what,
161 produce< result_t >(
162 sequence(
163 token_p() >> &result_t::first,
164 symbol('/'),
165 token_p() >> &result_t::second
166 )
167 )
168 );
169 };
170
171 {
172 const auto result = try_parse( "text/plain" );
173
174 REQUIRE( result.first );
175 REQUIRE( "text" == result.second.first );
176 REQUIRE( "plain" == result.second.second );
177 }
178
179 {
180 const auto result = try_parse( "text/*" );
181
182 REQUIRE( result.first );
183 REQUIRE( "text" == result.second.first );
184 REQUIRE( "*" == result.second.second );
185 }
186 }
187
188 TEST_CASE( "not", "[token][not]" )
189 {
190 using namespace restinio::http_field_parsers;
191
192 struct result_t
193 {
194 std::string first;
195 std::string second;
196 std::string third;
197 };
198
__anond34307e20502( restinio::string_view_t what ) 199 const auto try_parse = []( restinio::string_view_t what ) {
200 return restinio::easy_parser::try_parse( what,
201 produce< result_t >(
202 token_p() >> &result_t::first,
203 symbol('/'),
204 token_p() >> &result_t::second,
205 not_clause(
206 symbol(';'),
207 symbol('q')
208 ),
209 maybe(
210 symbol(';'),
211 token_p() >> &result_t::third
212 )
213 )
214 );
215 };
216
217 {
218 const auto result = try_parse( "text/plain" );
219
220 REQUIRE( result.first );
221 REQUIRE( "text" == result.second.first );
222 REQUIRE( "plain" == result.second.second );
223 }
224
225 {
226 const auto result = try_parse( "text/plain;default" );
227
228 REQUIRE( result.first );
229 REQUIRE( "text" == result.second.first );
230 REQUIRE( "plain" == result.second.second );
231 REQUIRE( "default" == result.second.third );
232 }
233
234 {
235 const auto result = try_parse( "text/plain;q" );
236
237 REQUIRE( !result.first );
238 }
239
240 {
241 const auto result = try_parse( "text/plain;qq" );
242
243 REQUIRE( !result.first );
244 }
245
246 {
247 const auto result = try_parse( "text/plain;Q" );
248
249 REQUIRE( result.first );
250 REQUIRE( "text" == result.second.first );
251 REQUIRE( "plain" == result.second.second );
252 REQUIRE( "Q" == result.second.third );
253 }
254 }
255
256 TEST_CASE( "and", "[token][and]" )
257 {
258 using namespace restinio::http_field_parsers;
259
260 struct result_t
261 {
262 std::string first;
263 std::string second;
264 std::string third;
265 };
266
__anond34307e20602( restinio::string_view_t what ) 267 const auto try_parse = []( restinio::string_view_t what ) {
268 return restinio::easy_parser::try_parse( what,
269 produce< result_t >(
270 token_p() >> &result_t::first,
271 symbol('/'),
272 token_p() >> &result_t::second,
273 and_clause(
274 symbol(';'),
275 symbol('q')
276 ),
277 symbol(';'),
278 token_p() >> &result_t::third
279 )
280 );
281 };
282
283 {
284 const auto result = try_parse( "text/plain" );
285
286 REQUIRE( !result.first );
287 }
288
289 {
290 const auto result = try_parse( "text/plain;default" );
291
292 REQUIRE( !result.first );
293 }
294
295 {
296 const auto result = try_parse( "text/plain;q" );
297
298 REQUIRE( result.first );
299 REQUIRE( "text" == result.second.first );
300 REQUIRE( "plain" == result.second.second );
301 REQUIRE( "q" == result.second.third );
302 }
303
304 {
305 const auto result = try_parse( "text/plain;qq" );
306
307 REQUIRE( result.first );
308 REQUIRE( "text" == result.second.first );
309 REQUIRE( "plain" == result.second.second );
310 REQUIRE( "qq" == result.second.third );
311 }
312
313 {
314 const auto result = try_parse( "text/plain;Q" );
315
316 REQUIRE( !result.first );
317 }
318 }
319
320 TEST_CASE( "alternatives with symbol", "[alternatives][symbol][field_setter]" )
321 {
322 using namespace restinio::http_field_parsers;
323
__anond34307e20702(restinio::string_view_t what) 324 const auto try_parse = [](restinio::string_view_t what) {
325 return restinio::easy_parser::try_parse(
326 what,
327 produce< media_type_t >(
328 token_p() >> &media_type_t::m_type,
329 alternatives(
330 symbol('/'),
331 symbol('='),
332 symbol('[')
333 ),
334 token_p() >> &media_type_t::m_subtype )
335 );
336 };
337
338 {
339 const auto result = try_parse( "multipart/form-data" );
340 REQUIRE( result.first );
341 REQUIRE( "multipart" == result.second.m_type );
342 REQUIRE( "form-data" == result.second.m_subtype );
343 }
344
345 {
346 const auto result = try_parse( "multipart=form-data" );
347 REQUIRE( result.first );
348 REQUIRE( "multipart" == result.second.m_type );
349 REQUIRE( "form-data" == result.second.m_subtype );
350 }
351
352 {
353 const auto result = try_parse( "multipart[form-data" );
354 REQUIRE( result.first );
355 REQUIRE( "multipart" == result.second.m_type );
356 REQUIRE( "form-data" == result.second.m_subtype );
357 }
358
359 {
360 const auto result = try_parse( "multipart(form-data" );
361 REQUIRE( !result.first );
362 }
363 }
364
365 TEST_CASE( "produce media_type", "[produce][media_type]" )
366 {
367 using namespace restinio::http_field_parsers;
368
369 struct media_type_holder_t {
370 media_type_t m_media;
371 };
372
__anond34307e20802(restinio::string_view_t what) 373 const auto try_parse = [](restinio::string_view_t what) {
374 return restinio::easy_parser::try_parse(
375 what,
376 produce< media_type_holder_t >(
377 produce< media_type_t >(
378 token_p() >> &media_type_t::m_type,
379 symbol('/'),
380 token_p() >> &media_type_t::m_subtype
381 ) >> &media_type_holder_t::m_media
382 )
383 );
384 };
385
386 {
387 const auto result = try_parse( "multipart/form-data" );
388 REQUIRE( result.first );
389 REQUIRE( "multipart" == result.second.m_media.m_type );
390 REQUIRE( "form-data" == result.second.m_media.m_subtype );
391 }
392
393 {
394 const auto result = try_parse( "*/form-data" );
395 REQUIRE( result.first );
396 REQUIRE( "*" == result.second.m_media.m_type );
397 REQUIRE( "form-data" == result.second.m_media.m_subtype );
398 }
399
400 {
401 const auto result = try_parse( "multipart/*" );
402 REQUIRE( result.first );
403 REQUIRE( "multipart" == result.second.m_media.m_type );
404 REQUIRE( "*" == result.second.m_media.m_subtype );
405 }
406
407 {
408 const auto result = try_parse( "*/*" );
409 REQUIRE( result.first );
410 REQUIRE( "*" == result.second.m_media.m_type );
411 REQUIRE( "*" == result.second.m_media.m_subtype );
412 }
413 }
414
415 TEST_CASE( "simple repeat (vector target)", "[repeat][vector]" )
416 {
417 using namespace restinio::http_field_parsers;
418
419 struct pairs_holder_t
420 {
421 using value_t = std::pair<std::string, std::string>;
422 using container_t = std::vector< value_t >;
423
424 container_t m_pairs;
425 };
426
427 const auto result = restinio::easy_parser::try_parse(
428 ";name1=value;name2=value2",
429 produce< pairs_holder_t >(
430 produce< pairs_holder_t::container_t >(
431 repeat( 0, N,
432 produce< pairs_holder_t::value_t >(
433 symbol(';'),
434 token_p() >> &pairs_holder_t::value_t::first,
435 symbol('='),
436 token_p() >> &pairs_holder_t::value_t::second
437 ) >> to_container()
438 )
439 ) >> &pairs_holder_t::m_pairs
440 )
441 );
442
443 REQUIRE( result.first );
444 REQUIRE( 2 == result.second.m_pairs.size() );
445 REQUIRE( "name1" == result.second.m_pairs[0].first );
446 REQUIRE( "value" == result.second.m_pairs[0].second );
447 REQUIRE( "name2" == result.second.m_pairs[1].first );
448 REQUIRE( "value2" == result.second.m_pairs[1].second );
449 }
450
451 TEST_CASE( "simple repeat (map target)", "[repeat][map]" )
452 {
453 using namespace restinio::http_field_parsers;
454
455 struct pairs_holder_t
456 {
457 using value_t = std::pair<std::string, std::string>;
458 using container_t = std::map< std::string, std::string >;
459
460 std::map< std::string, std::string > m_pairs;
461 };
462
463 const auto result = restinio::easy_parser::try_parse(
464 ";name1=value;name2=value2",
465 produce< pairs_holder_t >(
466 produce< pairs_holder_t::container_t >(
467 repeat( 0, N,
468 produce< pairs_holder_t::value_t >(
469 symbol(';'),
470 token_p() >> &pairs_holder_t::value_t::first,
471 symbol('='),
472 token_p() >> &pairs_holder_t::value_t::second
473 ) >> to_container()
474 )
475 ) >> &pairs_holder_t::m_pairs
476 )
477 );
478
479 REQUIRE( result.first );
480 REQUIRE( 2 == result.second.m_pairs.size() );
481
482 const std::map< std::string, std::string > expected{
483 { "name1", "value" }, { "name2", "value2" }
484 };
485
486 REQUIRE( expected == result.second.m_pairs );
487 }
488
489 TEST_CASE( "simple repeat (string)", "[repeat][string][symbol_producer]" )
490 {
491 using namespace restinio::http_field_parsers;
492
__anond34307e20902( restinio::string_view_t what ) 493 const auto try_parse = []( restinio::string_view_t what ) {
494 return restinio::easy_parser::try_parse(
495 what,
496 produce< std::string >(
497 repeat( 3, 7,
498 symbol_p('*') >> to_container()
499 )
500 )
501 );
502 };
503
504 {
505 const auto result = try_parse( "" );
506 REQUIRE( !result.first );
507 }
508
509 {
510 const auto result = try_parse( "**" );
511 REQUIRE( !result.first );
512 }
513
514 {
515 const auto result = try_parse( "***" );
516 REQUIRE( result.first );
517 REQUIRE( "***" == result.second );
518 }
519
520 {
521 const auto result = try_parse( "*****" );
522 REQUIRE( result.first );
523 REQUIRE( "*****" == result.second );
524 }
525
526 {
527 const auto result = try_parse( "*******" );
528 REQUIRE( result.first );
529 REQUIRE( "*******" == result.second );
530 }
531
532 {
533 const auto result = try_parse( "********" );
534 REQUIRE( !result.first );
535 }
536 }
537
538 TEST_CASE( "simple content_type", "[content_type]" )
539 {
540 using namespace restinio::http_field_parsers;
541
__anond34307e20a02(restinio::string_view_t what) 542 const auto try_parse = [](restinio::string_view_t what) {
543 return restinio::easy_parser::try_parse(
544 what,
545 produce< content_type_t >(
546 produce< media_type_t >(
547 token_p() >> to_lower() >> &media_type_t::m_type,
548 symbol('/'),
549 token_p() >> to_lower() >> &media_type_t::m_subtype
550 ) >> &content_type_t::m_media_type,
551
552 produce< std::map<std::string, std::string> >(
553 repeat( 0, N,
554 produce< std::pair<std::string, std::string> >(
555 symbol(';'),
556 ows(),
557
558 token_p() >> to_lower() >>
559 &std::pair<std::string, std::string>::first,
560
561 symbol('='),
562
563 produce< std::string >(
564 alternatives(
565 token_p()
566 >> to_lower()
567 >> as_result(),
568 quoted_string_p()
569 >> as_result()
570 )
571 ) >> &std::pair<std::string, std::string>::second
572 ) >> to_container()
573 )
574 ) >> &content_type_t::m_parameters
575 )
576 );
577 };
578
579 {
580 const auto result = try_parse( "text/plain" );
581
582 REQUIRE( result.first );
583 REQUIRE( "text" == result.second.m_media_type.m_type );
584 REQUIRE( "plain" == result.second.m_media_type.m_subtype );
585 REQUIRE( result.second.m_parameters.empty() );
586 }
587
588 {
589 const auto result = try_parse( "text/plain; charset=utf-8" );
590
591 REQUIRE( result.first );
592 REQUIRE( "text" == result.second.m_media_type.m_type );
593 REQUIRE( "plain" == result.second.m_media_type.m_subtype );
594 REQUIRE( !result.second.m_parameters.empty() );
595
596 const std::map< std::string, std::string > expected{
597 { "charset", "utf-8" }
598 };
599
600 REQUIRE( expected == result.second.m_parameters );
601 }
602
603 {
604 const auto result = try_parse( "text/plain;charset=utf-8" );
605
606 REQUIRE( result.first );
607 REQUIRE( "text" == result.second.m_media_type.m_type );
608 REQUIRE( "plain" == result.second.m_media_type.m_subtype );
609 REQUIRE( !result.second.m_parameters.empty() );
610
611 const std::map< std::string, std::string > expected{
612 { "charset", "utf-8" }
613 };
614
615 REQUIRE( expected == result.second.m_parameters );
616 }
617
618 {
619 const auto result = try_parse(
620 "multipart/form-data; charset=utf-8; boundary=---123456" );
621
622 REQUIRE( result.first );
623 REQUIRE( "multipart" == result.second.m_media_type.m_type );
624 REQUIRE( "form-data" == result.second.m_media_type.m_subtype );
625 REQUIRE( !result.second.m_parameters.empty() );
626
627 const std::map< std::string, std::string > expected{
628 { "charset", "utf-8" }, { "boundary", "---123456" }
629 };
630
631 REQUIRE( expected == result.second.m_parameters );
632 }
633
634 {
635 const auto result = try_parse(
636 R"(multipart/form-data; charset=utf-8; boundary="Text with space!")" );
637
638 REQUIRE( result.first );
639 REQUIRE( "multipart" == result.second.m_media_type.m_type );
640 REQUIRE( "form-data" == result.second.m_media_type.m_subtype );
641 REQUIRE( !result.second.m_parameters.empty() );
642
643 const std::map< std::string, std::string > expected{
644 { "charset", "utf-8" }, { "boundary", "Text with space!" }
645 };
646
647 REQUIRE( expected == result.second.m_parameters );
648 }
649
650 {
651 const auto result = try_parse(
652 R"(multipart/form-data; charset=utf-8; boundary="Text with space!")" );
653
654 REQUIRE( result.first );
655 REQUIRE( "multipart" == result.second.m_media_type.m_type );
656 REQUIRE( "form-data" == result.second.m_media_type.m_subtype );
657 REQUIRE( !result.second.m_parameters.empty() );
658
659 const std::map< std::string, std::string > expected{
660 { "charset", "utf-8" }, { "boundary", "Text with space!" }
661 };
662
663 REQUIRE( expected == result.second.m_parameters );
664 }
665
666 {
667 const auto result = try_parse(
668 R"(MultiPart/Form-Data; CharSet=utf-8; BOUNDARY="Text with space!")" );
669
670 REQUIRE( result.first );
671 REQUIRE( "multipart" == result.second.m_media_type.m_type );
672 REQUIRE( "form-data" == result.second.m_media_type.m_subtype );
673 REQUIRE( !result.second.m_parameters.empty() );
674
675 const std::map< std::string, std::string > expected{
676 { "charset", "utf-8" }, { "boundary", "Text with space!" }
677 };
678
679 REQUIRE( expected == result.second.m_parameters );
680 }
681 }
682
683 TEST_CASE( "sequence with optional", "[optional][simple]" )
684 {
685 using namespace restinio::http_field_parsers;
686
__anond34307e20b02(restinio::string_view_t what) 687 const auto try_parse = [](restinio::string_view_t what) {
688 return restinio::easy_parser::try_parse(
689 what,
690 produce< value_with_opt_params_t >(
691 token_p() >> to_lower() >>
692 &value_with_opt_params_t::m_value,
693
694 produce< value_with_opt_params_t::param_storage_t >(
695 repeat( 0, N,
696 produce< value_with_opt_params_t::param_t >(
697 symbol(';'),
698 ows(),
699
700 token_p() >> to_lower() >>
701 &value_with_opt_params_t::param_t::first,
702
703 produce< restinio::optional_t<std::string> >(
704 maybe(
705 symbol('='),
706
707 alternatives(
708 token_p() >> to_lower() >> as_result(),
709 quoted_string_p() >> as_result()
710 )
711 )
712 ) >> &value_with_opt_params_t::param_t::second
713 ) >> to_container()
714 )
715 ) >> &value_with_opt_params_t::m_params
716 )
717 );
718 };
719
720 {
721 const auto result = try_parse("just-value");
722
723 REQUIRE( result.first );
724 REQUIRE( "just-value" == result.second.m_value );
725 REQUIRE( result.second.m_params.empty() );
726 }
727
728 {
729 const auto result = try_parse("just-value;one");
730
731 REQUIRE( result.first );
732 REQUIRE( "just-value" == result.second.m_value );
733
734 REQUIRE( 1 == result.second.m_params.size() );
735
736 REQUIRE( "one" == result.second.m_params[0].first );
737 REQUIRE( !result.second.m_params[0].second );
738 }
739
740 {
741 const auto result = try_parse("just-value;one; two=two;three; "
742 "four=\"four = 4\"");
743
744 REQUIRE( result.first );
745 REQUIRE( "just-value" == result.second.m_value );
746
747 REQUIRE( 4 == result.second.m_params.size() );
748
749 REQUIRE( "one" == result.second.m_params[0].first );
750 REQUIRE( !result.second.m_params[0].second );
751
752 REQUIRE( "two" == result.second.m_params[1].first );
753 REQUIRE( result.second.m_params[1].second );
754 REQUIRE( "two" == *(result.second.m_params[1].second) );
755
756 REQUIRE( "three" == result.second.m_params[2].first );
757 REQUIRE( !result.second.m_params[2].second );
758
759 REQUIRE( "four" == result.second.m_params[3].first );
760 REQUIRE( result.second.m_params[3].second );
761 REQUIRE( "four = 4" == *(result.second.m_params[3].second) );
762 }
763 }
764
765 TEST_CASE( "rollback on backtracking", "[rollback][alternative]" )
766 {
767 using namespace restinio::http_field_parsers;
768
769 struct accumulator_t {
770 std::string m_one;
771 std::string m_two;
772 std::string m_three;
773 };
774
__anond34307e20c02( restinio::string_view_t what ) 775 const auto try_parse = []( restinio::string_view_t what ) {
776 return restinio::easy_parser::try_parse( what,
777 produce< accumulator_t >(
778 alternatives(
779 sequence(
780 symbol('1'), symbol('='),
781 token_p() >> &accumulator_t::m_one,
782 symbol(';') ),
783 sequence(
784 symbol('1'), symbol('='),
785 token_p() >> &accumulator_t::m_one,
786 symbol(','), symbol('2'), symbol('='),
787 token_p() >> &accumulator_t::m_two,
788 symbol(';') ),
789 sequence(
790 symbol('1'), symbol('='),
791 token_p() >> &accumulator_t::m_one,
792 symbol(','), symbol('2'), symbol('='),
793 token_p() >> &accumulator_t::m_two,
794 symbol(','), symbol('3'), symbol('='),
795 token_p() >> &accumulator_t::m_three,
796 symbol(';') ),
797 sequence(
798 symbol('1'), symbol('='),
799 token_p() >> skip(),
800 symbol(','), symbol('2'), symbol('='),
801 token_p() >> skip(),
802 symbol(','), symbol('3'), symbol('='),
803 token_p() >> &accumulator_t::m_three,
804 symbol(','), symbol(',') )
805 )
806 )
807 );
808 };
809
810 {
811 const auto result = try_parse("1=a;");
812
813 REQUIRE( result.first );
814 REQUIRE( "a" == result.second.m_one );
815 }
816
817 {
818 const auto result = try_parse("1=a2,2=b2,3=c2;");
819
820 REQUIRE( result.first );
821 REQUIRE( "a2" == result.second.m_one );
822 REQUIRE( "b2" == result.second.m_two );
823 REQUIRE( "c2" == result.second.m_three );
824 }
825
826 {
827 const auto result = try_parse("1=aa,2=bb,3=cc,,");
828
829 REQUIRE( result.first );
830 REQUIRE( "" == result.second.m_one );
831 REQUIRE( "" == result.second.m_two );
832 REQUIRE( "cc" == result.second.m_three );
833 }
834 }
835
836 TEST_CASE( "qvalue", "[qvalue]" )
837 {
838 using namespace restinio::http_field_parsers;
839 using untrusted = qvalue_t::untrusted;
840
__anond34307e20d02( restinio::string_view_t what ) 841 const auto try_parse = []( restinio::string_view_t what ) {
842 return restinio::easy_parser::try_parse( what, qvalue_p() );
843 };
844
845 {
846 const auto result = try_parse( "" );
847
848 REQUIRE( !result.first );
849 }
850
851 {
852 const auto result = try_parse( "0" );
853
854 REQUIRE( result.first );
855 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
856 }
857
858 {
859 const auto result = try_parse( "1" );
860
861 REQUIRE( result.first );
862 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
863 }
864
865 {
866 const auto result = try_parse( "0 " );
867
868 REQUIRE( result.first );
869 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
870 }
871
872 {
873 const auto result = try_parse( "1 " );
874
875 REQUIRE( result.first );
876 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
877 }
878
879 {
880 const auto result = try_parse( "0." );
881
882 REQUIRE( result.first );
883 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
884 }
885
886 {
887 const auto result = try_parse( "1." );
888
889 REQUIRE( result.first );
890 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
891 }
892
893 {
894 const auto result = try_parse( "0.000" );
895
896 REQUIRE( result.first );
897 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
898 }
899
900 {
901 const auto result = try_parse( "0.1 " );
902
903 REQUIRE( result.first );
904 REQUIRE( qvalue_t{untrusted{100u}} == result.second );
905 }
906
907 {
908 const auto result = try_parse( "0.01 " );
909
910 REQUIRE( result.first );
911 REQUIRE( qvalue_t{untrusted{10u}} == result.second );
912 }
913
914 {
915 const auto result = try_parse( "0.001 " );
916
917 REQUIRE( result.first );
918 REQUIRE( qvalue_t{untrusted{1u}} == result.second );
919 }
920
921 {
922 const auto result = try_parse( "1.000" );
923
924 REQUIRE( result.first );
925 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
926 }
927
928 {
929 const auto result = try_parse( "1.0 " );
930
931 REQUIRE( result.first );
932 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
933 }
934
935 {
936 const auto result = try_parse( "1.00 " );
937
938 REQUIRE( result.first );
939 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
940 }
941
942 {
943 const auto result = try_parse( "1.000 " );
944
945 REQUIRE( result.first );
946 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
947 }
948
949 {
950 const auto result = try_parse( "0.001" );
951
952 REQUIRE( result.first );
953 REQUIRE( qvalue_t{untrusted{1u}} == result.second );
954 }
955
956 {
957 const auto result = try_parse( "1.001" );
958
959 REQUIRE( !result.first );
960 }
961
962 {
963 const auto result = try_parse( "0.321" );
964
965 REQUIRE( result.first );
966 REQUIRE( qvalue_t{untrusted{321u}} == result.second );
967 REQUIRE( "0.321" == result.second.as_string() );
968 }
969 }
970
971 TEST_CASE( "weight", "[qvalue][weight]" )
972 {
973 using namespace restinio::http_field_parsers;
974 using untrusted = qvalue_t::untrusted;
975
__anond34307e20e02( restinio::string_view_t what ) 976 const auto try_parse = []( restinio::string_view_t what ) {
977 return restinio::easy_parser::try_parse( what, weight_p() );
978 };
979
980 {
981 const auto result = try_parse( "Q=0" );
982
983 REQUIRE( !result.first );
984 }
985
986 {
987 const auto result = try_parse( "q=0" );
988
989 REQUIRE( !result.first );
990 }
991
992 {
993 const auto result = try_parse( ";Q" );
994
995 REQUIRE( !result.first );
996 }
997
998 {
999 const auto result = try_parse( ";q" );
1000
1001 REQUIRE( !result.first );
1002 }
1003
1004 {
1005 const auto result = try_parse( ";Q=" );
1006
1007 REQUIRE( !result.first );
1008 }
1009
1010 {
1011 const auto result = try_parse( ";q=" );
1012
1013 REQUIRE( !result.first );
1014 }
1015
1016 {
1017 const auto result = try_parse( ";Q=0" );
1018
1019 REQUIRE( result.first );
1020 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
1021 }
1022
1023 {
1024 const auto result = try_parse( ";q=0" );
1025
1026 REQUIRE( result.first );
1027 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
1028 }
1029
1030 {
1031 const auto result = try_parse( " ;Q=0" );
1032
1033 REQUIRE( result.first );
1034 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
1035 }
1036
1037 {
1038 const auto result = try_parse( "; q=0" );
1039
1040 REQUIRE( result.first );
1041 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
1042 }
1043
1044 {
1045 const auto result = try_parse( " ; q=0" );
1046
1047 REQUIRE( result.first );
1048 REQUIRE( qvalue_t{untrusted{0u}} == result.second );
1049 }
1050
1051 {
1052 const auto result = try_parse( ";Q=1" );
1053
1054 REQUIRE( result.first );
1055 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
1056 }
1057
1058 {
1059 const auto result = try_parse( ";q=1" );
1060
1061 REQUIRE( result.first );
1062 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
1063 }
1064
1065 {
1066 const auto result = try_parse( ";q=1.0 " );
1067
1068 REQUIRE( result.first );
1069 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
1070 }
1071
1072 {
1073 const auto result = try_parse( " ; q=1.00 " );
1074
1075 REQUIRE( result.first );
1076 REQUIRE( qvalue_t{untrusted{1000u}} == result.second );
1077 }
1078 }
1079
1080 TEST_CASE( "non_empty_comma_separated_list_producer",
1081 "[non_empty_comma_separated_list_producer]" )
1082 {
1083 using namespace restinio::http_field_parsers;
1084
__anond34307e20f02( restinio::string_view_t what ) 1085 const auto try_parse = []( restinio::string_view_t what ) {
1086 const auto media_type = produce< media_type_t >(
1087 token_p() >> to_lower() >> &media_type_t::m_type,
1088 symbol('/'),
1089 token_p() >> to_lower() >> &media_type_t::m_subtype );
1090
1091 return restinio::easy_parser::try_parse(
1092 what,
1093 non_empty_comma_separated_list_p<
1094 std::vector< media_type_t > >( media_type )
1095 );
1096 };
1097
1098 {
1099 const auto result = try_parse( "" );
1100
1101 REQUIRE( !result.first );
1102 }
1103
1104 {
1105 const auto result = try_parse( "," );
1106
1107 REQUIRE( !result.first );
1108 }
1109
1110 {
1111 const auto result = try_parse( ",,,," );
1112
1113 REQUIRE( !result.first );
1114 }
1115
1116 {
1117 const auto result = try_parse( ", , , , " );
1118
1119 REQUIRE( !result.first );
1120 REQUIRE( result.second.empty() );
1121 }
1122
1123 {
1124 const auto result = try_parse( "text/plain" );
1125
1126 REQUIRE( result.first );
1127
1128 std::vector< media_type_t > expected{
1129 { "text", "plain" }
1130 };
1131
1132 REQUIRE( expected == result.second );
1133 }
1134
1135 {
1136 const auto result = try_parse( ", ,text/plain" );
1137
1138 REQUIRE( result.first );
1139
1140 std::vector< media_type_t > expected{
1141 { "text", "plain" }
1142 };
1143
1144 REQUIRE( expected == result.second );
1145 }
1146
1147 {
1148 const auto result = try_parse( ", , text/plain , */*,, , , text/*," );
1149
1150 REQUIRE( result.first );
1151
1152 std::vector< media_type_t > expected{
1153 { "text", "plain" },
1154 { "*", "*" },
1155 { "text", "*" }
1156 };
1157
1158 REQUIRE( expected == result.second );
1159 }
1160 }
1161
1162 TEST_CASE( "maybe_empty_comma_separated_list_producer",
1163 "[maybe_empty_comma_separated_list_producer]" )
1164 {
1165 using namespace restinio::http_field_parsers;
1166
__anond34307e21002( restinio::string_view_t what ) 1167 const auto try_parse = []( restinio::string_view_t what ) {
1168 const auto media_type = produce< media_type_t >(
1169 token_p() >> to_lower() >> &media_type_t::m_type,
1170 symbol('/'),
1171 token_p() >> to_lower() >> &media_type_t::m_subtype );
1172
1173 return restinio::easy_parser::try_parse(
1174 what,
1175 maybe_empty_comma_separated_list_p<
1176 std::vector< media_type_t > >( media_type )
1177 );
1178 };
1179
1180 {
1181 const auto result = try_parse( "" );
1182
1183 REQUIRE( result.first );
1184 REQUIRE( result.second.empty() );
1185 }
1186
1187 {
1188 const auto result = try_parse( "," );
1189
1190 REQUIRE( result.first );
1191 REQUIRE( result.second.empty() );
1192 }
1193
1194 {
1195 const auto result = try_parse( ",,,," );
1196
1197 REQUIRE( result.first );
1198 REQUIRE( result.second.empty() );
1199 }
1200
1201 {
1202 const auto result = try_parse( ", , , , " );
1203
1204 REQUIRE( result.first );
1205 REQUIRE( result.second.empty() );
1206 }
1207
1208 {
1209 const auto result = try_parse( "text/plain" );
1210
1211 REQUIRE( result.first );
1212
1213 std::vector< media_type_t > expected{
1214 { "text", "plain" }
1215 };
1216
1217 REQUIRE( expected == result.second );
1218 }
1219
1220 {
1221 const auto result = try_parse( ", ,text/plain" );
1222
1223 REQUIRE( result.first );
1224
1225 std::vector< media_type_t > expected{
1226 { "text", "plain" }
1227 };
1228
1229 REQUIRE( expected == result.second );
1230 }
1231
1232 {
1233 const auto result = try_parse( ", , text/plain , */*,, , , text/*," );
1234
1235 REQUIRE( result.first );
1236
1237 std::vector< media_type_t > expected{
1238 { "text", "plain" },
1239 { "*", "*" },
1240 { "text", "*" }
1241 };
1242
1243 REQUIRE( expected == result.second );
1244 }
1245 }
1246
1247 TEST_CASE( "Media-Type", "[media-type]" )
1248 {
1249 using namespace restinio::http_field_parsers;
1250 using namespace std::string_literals;
1251
1252 {
1253 const auto result = media_type_value_t::try_parse(
1254 "" );
1255
1256 REQUIRE( !result.first );
1257 }
1258
1259 {
1260 const auto result = media_type_value_t::try_parse(
1261 "text/" );
1262
1263 REQUIRE( !result.first );
1264 }
1265
1266 {
1267 const auto result = media_type_value_t::try_parse(
1268 "/plain" );
1269
1270 REQUIRE( !result.first );
1271 }
1272
1273 {
1274 const auto result = media_type_value_t::try_parse(
1275 "text/plain" );
1276
1277 REQUIRE( result.first );
1278
1279 REQUIRE( "text" == result.second.m_type );
1280 REQUIRE( "plain" == result.second.m_subtype );
1281 REQUIRE( result.second.m_parameters.empty() );
1282 }
1283
1284 {
1285 const auto result = media_type_value_t::try_parse(
1286 "TexT/pLAIn" );
1287
1288 REQUIRE( result.first );
1289
1290 REQUIRE( "text" == result.second.m_type );
1291 REQUIRE( "plain" == result.second.m_subtype );
1292 REQUIRE( result.second.m_parameters.empty() );
1293 }
1294
1295 {
1296 const auto result = media_type_value_t::try_parse(
1297 "text/*; CharSet=utf-8 ; Alternative-Coding=\"Bla Bla Bla\"" );
1298
1299 REQUIRE( result.first );
1300
1301 REQUIRE( "text" == result.second.m_type );
1302 REQUIRE( "*" == result.second.m_subtype );
1303
1304 media_type_value_t::parameter_container_t expected{
1305 { "charset"s, "utf-8"s },
1306 { "alternative-coding"s, "Bla Bla Bla"s }
1307 };
1308 REQUIRE( expected == result.second.m_parameters );
1309 }
1310
1311 {
1312 const auto result = media_type_value_t::try_parse(
1313 "*/*;CharSet=utf-8;Alternative-Coding=\"Bla Bla Bla\";foO=BaZ" );
1314
1315 REQUIRE( result.first );
1316
1317 REQUIRE( "*" == result.second.m_type );
1318 REQUIRE( "*" == result.second.m_subtype );
1319
1320 media_type_value_t::parameter_container_t expected{
1321 { "charset"s, "utf-8"s },
1322 { "alternative-coding"s, "Bla Bla Bla"s },
1323 { "foo"s, "BaZ"s }
1324 };
1325 REQUIRE( expected == result.second.m_parameters );
1326 }
1327 }
1328
1329 TEST_CASE( "Content-Type", "[media-type][content-type]" )
1330 {
1331 using namespace restinio::http_field_parsers;
1332 using namespace std::string_literals;
1333
1334 {
1335 const auto result = content_type_value_t::try_parse(
1336 "text/plain" );
1337
1338 REQUIRE( result.first );
1339
1340 REQUIRE( "text" == result.second.m_media_type.m_type );
1341 REQUIRE( "plain" == result.second.m_media_type.m_subtype );
1342 REQUIRE( result.second.m_media_type.m_parameters.empty() );
1343 }
1344
1345 {
1346 const auto result = content_type_value_t::try_parse(
1347 "TexT/pLAIn" );
1348
1349 REQUIRE( result.first );
1350
1351 REQUIRE( "text" == result.second.m_media_type.m_type );
1352 REQUIRE( "plain" == result.second.m_media_type.m_subtype );
1353 REQUIRE( result.second.m_media_type.m_parameters.empty() );
1354 }
1355
1356 {
1357 const auto result = content_type_value_t::try_parse(
1358 "text/*; CharSet=utf-8 ; Alternative-Coding=\"Bla Bla Bla\"" );
1359
1360 REQUIRE( result.first );
1361
1362 REQUIRE( "text" == result.second.m_media_type.m_type );
1363 REQUIRE( "*" == result.second.m_media_type.m_subtype );
1364
1365 media_type_value_t::parameter_container_t expected{
1366 { "charset"s, "utf-8"s },
1367 { "alternative-coding"s, "Bla Bla Bla"s }
1368 };
1369 REQUIRE( expected == result.second.m_media_type.m_parameters );
1370 }
1371
1372 {
1373 const auto result = content_type_value_t::try_parse(
1374 "*/*;CharSet=utf-8;Alternative-Coding=\"Bla Bla Bla\";foO=BaZ" );
1375
1376 REQUIRE( result.first );
1377
1378 REQUIRE( "*" == result.second.m_media_type.m_type );
1379 REQUIRE( "*" == result.second.m_media_type.m_subtype );
1380
1381 media_type_value_t::parameter_container_t expected{
1382 { "charset"s, "utf-8"s },
1383 { "alternative-coding"s, "Bla Bla Bla"s },
1384 { "foo"s, "BaZ"s }
1385 };
1386 REQUIRE( expected == result.second.m_media_type.m_parameters );
1387 }
1388 }
1389
1390 TEST_CASE( "Cache-Control Field", "[cache-control]" )
1391 {
1392 using namespace restinio::http_field_parsers;
1393 using namespace std::string_literals;
1394
1395 {
1396 const auto result = cache_control_value_t::try_parse(
1397 "" );
1398
1399 REQUIRE( !result.first );
1400 }
1401
1402 {
1403 const auto result = cache_control_value_t::try_parse(
1404 "," );
1405
1406 REQUIRE( !result.first );
1407 }
1408
1409 {
1410 const auto result = cache_control_value_t::try_parse(
1411 ",, , , , " );
1412
1413 REQUIRE( !result.first );
1414 }
1415
1416 {
1417 const auto result = cache_control_value_t::try_parse(
1418 "max-age=5" );
1419
1420 REQUIRE( result.first );
1421
1422 cache_control_value_t::directive_container_t expected_directives{
1423 { "max-age"s, "5"s },
1424 };
1425
1426 REQUIRE( expected_directives == result.second.m_directives );
1427 }
1428
1429 {
1430 const auto result = cache_control_value_t::try_parse(
1431 "max-age=5, no-transform, only-if-cached, min-fresh=20" );
1432
1433 REQUIRE( result.first );
1434
1435 cache_control_value_t::directive_container_t expected_directives{
1436 { "max-age"s, "5"s },
1437 { "no-transform"s, restinio::nullopt },
1438 { "only-if-cached"s, restinio::nullopt },
1439 { "min-fresh"s, "20"s }
1440 };
1441
1442 REQUIRE( expected_directives == result.second.m_directives );
1443 }
1444
1445 {
1446 const auto result = cache_control_value_t::try_parse(
1447 ", , , , max-age=5, ,,, no-transform, only-if-cached, min-fresh=20,,,, " );
1448
1449 REQUIRE( result.first );
1450
1451 cache_control_value_t::directive_container_t expected_directives{
1452 { "max-age"s, "5"s },
1453 { "no-transform"s, restinio::nullopt },
1454 { "only-if-cached"s, restinio::nullopt },
1455 { "min-fresh"s, "20"s }
1456 };
1457
1458 REQUIRE( expected_directives == result.second.m_directives );
1459 }
1460 }
1461
1462 TEST_CASE( "Content-Encoding", "[content-encoding]" )
1463 {
1464 using namespace restinio::http_field_parsers;
1465 using namespace std::string_literals;
1466
1467 {
1468 const auto result = content_encoding_value_t::try_parse(
1469 "" );
1470
1471 REQUIRE( !result.first );
1472 }
1473
1474 {
1475 const auto result = content_encoding_value_t::try_parse(
1476 "compress/" );
1477
1478 REQUIRE( !result.first );
1479 }
1480
1481 {
1482 const auto result = content_encoding_value_t::try_parse(
1483 "compress" );
1484
1485 REQUIRE( result.first );
1486
1487 const content_encoding_value_t::value_container_t expected{
1488 "compress"s
1489 };
1490
1491 REQUIRE( expected == result.second.m_values );
1492 }
1493
1494 {
1495 const auto result = content_encoding_value_t::try_parse(
1496 "X-Compress" );
1497
1498 REQUIRE( result.first );
1499
1500 const content_encoding_value_t::value_container_t expected{
1501 "x-compress"s
1502 };
1503
1504 REQUIRE( expected == result.second.m_values );
1505 }
1506
1507 {
1508 const auto result = content_encoding_value_t::try_parse(
1509 "gzip, X-Compress , deflate" );
1510
1511 REQUIRE( result.first );
1512
1513 const content_encoding_value_t::value_container_t expected{
1514 "gzip"s,
1515 "x-compress"s,
1516 "deflate"s
1517 };
1518
1519 REQUIRE( expected == result.second.m_values );
1520 }
1521 }
1522
1523 TEST_CASE( "Accept", "[media-type][accept]" )
1524 {
1525 using namespace restinio::http_field_parsers;
1526 using namespace std::string_literals;
1527
1528 {
1529 const auto result = accept_value_t::try_parse(
1530 "" );
1531
1532 REQUIRE( result.first );
1533
1534 REQUIRE( result.second.m_items.empty() );
1535 }
1536
1537 {
1538 const auto result = accept_value_t::try_parse(
1539 "text/" );
1540
1541 REQUIRE( !result.first );
1542 }
1543
1544 {
1545 const auto result = accept_value_t::try_parse(
1546 "/plain" );
1547
1548 REQUIRE( !result.first );
1549 }
1550
1551 {
1552 const auto result = accept_value_t::try_parse(
1553 "text/plain" );
1554
1555 REQUIRE( result.first );
1556
1557 REQUIRE( 1 == result.second.m_items.size() );
1558
1559 const auto & item = result.second.m_items[0];
1560
1561 REQUIRE( "text" == item.m_media_type.m_type );
1562 REQUIRE( "plain" == item.m_media_type.m_subtype );
1563 REQUIRE( item.m_media_type.m_parameters.empty() );
1564 }
1565
1566 {
1567 const auto result = accept_value_t::try_parse(
1568 "text/*; CharSet=utf-8 ; Alternative-Coding=\"Bla Bla Bla\"" );
1569
1570 REQUIRE( result.first );
1571
1572 REQUIRE( 1 == result.second.m_items.size() );
1573
1574 const auto & item = result.second.m_items[0];
1575
1576 REQUIRE( "text" == item.m_media_type.m_type );
1577 REQUIRE( "*" == item.m_media_type.m_subtype );
1578
1579 media_type_value_t::parameter_container_t expected{
1580 { "charset"s, "utf-8"s },
1581 { "alternative-coding"s, "Bla Bla Bla"s }
1582 };
1583 REQUIRE( expected == item.m_media_type.m_parameters );
1584 }
1585
1586 {
1587 const auto result = accept_value_t::try_parse(
1588 "text/*;CharSet=utf-8, application/json;charset=cp1251" );
1589
1590 REQUIRE( result.first );
1591
1592 REQUIRE( 2 == result.second.m_items.size() );
1593
1594 {
1595 const auto & item = result.second.m_items[0];
1596
1597 REQUIRE( "text" == item.m_media_type.m_type );
1598 REQUIRE( "*" == item.m_media_type.m_subtype );
1599
1600 media_type_value_t::parameter_container_t expected{
1601 { "charset"s, "utf-8"s },
1602 };
1603 REQUIRE( expected == item.m_media_type.m_parameters );
1604 }
1605
1606 {
1607 const auto & item = result.second.m_items[1];
1608
1609 REQUIRE( "application" == item.m_media_type.m_type );
1610 REQUIRE( "json" == item.m_media_type.m_subtype );
1611
1612 media_type_value_t::parameter_container_t expected{
1613 { "charset"s, "cp1251"s },
1614 };
1615 REQUIRE( expected == item.m_media_type.m_parameters );
1616 }
1617 }
1618
1619 {
1620 const auto result = accept_value_t::try_parse(
1621 "text/plain;q=0.5;signed;signature-method=sha512, "
1622 "text/*;CharSet=utf-8, "
1623 "application/json;charset=cp1251" );
1624
1625 REQUIRE( result.first );
1626
1627 REQUIRE( 3 == result.second.m_items.size() );
1628
1629 {
1630 const auto & item = result.second.m_items[0];
1631 REQUIRE( "text" == item.m_media_type.m_type );
1632 REQUIRE( "plain" == item.m_media_type.m_subtype );
1633 REQUIRE( item.m_media_type.m_parameters.empty() );
1634
1635 REQUIRE( item.m_weight );
1636 REQUIRE( qvalue_t{ qvalue_t::untrusted{500} } ==
1637 *item.m_weight );
1638
1639 accept_value_t::item_t::accept_ext_container_t expected{
1640 { "signed"s, restinio::nullopt },
1641 { "signature-method"s, "sha512"s }
1642 };
1643 REQUIRE( expected == item.m_accept_params );
1644 }
1645
1646 {
1647 const auto & item = result.second.m_items[1];
1648
1649 REQUIRE( "text" == item.m_media_type.m_type );
1650 REQUIRE( "*" == item.m_media_type.m_subtype );
1651
1652 media_type_value_t::parameter_container_t expected{
1653 { "charset"s, "utf-8"s },
1654 };
1655 REQUIRE( expected == item.m_media_type.m_parameters );
1656 }
1657
1658 {
1659 const auto & item = result.second.m_items[2];
1660
1661 REQUIRE( "application" == item.m_media_type.m_type );
1662 REQUIRE( "json" == item.m_media_type.m_subtype );
1663
1664 media_type_value_t::parameter_container_t expected{
1665 { "charset"s, "cp1251"s },
1666 };
1667 REQUIRE( expected == item.m_media_type.m_parameters );
1668 }
1669 }
1670 }
1671
1672 TEST_CASE( "Content-Disposition", "[content-disposition]" )
1673 {
1674 using namespace restinio::http_field_parsers;
1675 using namespace std::string_literals;
1676
1677 {
1678 const auto result = content_disposition_value_t::try_parse(
1679 "form-data" );
1680
1681 REQUIRE( result.first );
1682
1683 REQUIRE( "form-data" == result.second.m_value );
1684 REQUIRE( result.second.m_parameters.empty() );
1685 }
1686
1687 {
1688 const auto result = content_disposition_value_t::try_parse(
1689 "form-data; name=some-name" );
1690
1691 REQUIRE( result.first );
1692
1693 REQUIRE( "form-data" == result.second.m_value );
1694
1695 content_disposition_value_t::parameter_container_t expected{
1696 { "name"s, "some-name"s },
1697 };
1698 REQUIRE( expected == result.second.m_parameters );
1699 }
1700
1701 {
1702 const auto result = content_disposition_value_t::try_parse(
1703 "form-data; name=some-name ; filename=\"file\"" );
1704
1705 REQUIRE( result.first );
1706
1707 REQUIRE( "form-data" == result.second.m_value );
1708
1709 content_disposition_value_t::parameter_container_t expected{
1710 { "name"s, "some-name"s },
1711 { "filename"s, "file"s },
1712 };
1713 REQUIRE( expected == result.second.m_parameters );
1714 }
1715
1716 {
1717 const auto result = content_disposition_value_t::try_parse(
1718 "form-data; name=some-name ; filename=\"file\""
1719 ";filename*=\"another name\"");
1720
1721 REQUIRE( result.first );
1722
1723 REQUIRE( "form-data" == result.second.m_value );
1724
1725 content_disposition_value_t::parameter_container_t expected{
1726 { "name"s, "some-name"s },
1727 { "filename"s, "file"s },
1728 { "filename*"s, "another name"s },
1729 };
1730 REQUIRE( expected == result.second.m_parameters );
1731 }
1732 }
1733
1734