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