@@ -308,6 +308,201 @@ TEST(TrimTests, TrimStringTests) {
308308 EXPECT_TRUE (detail::trim_copy (" " ).empty ());
309309}
310310
311+ TEST (ParseAcceptHeaderTest, BasicAcceptParsing) {
312+ // Simple case without quality values
313+ std::vector<std::string> result1;
314+ EXPECT_TRUE (detail::parse_accept_header (
315+ " text/html,application/json,text/plain" , result1));
316+ EXPECT_EQ (result1.size (), 3 );
317+ EXPECT_EQ (result1[0 ], " text/html" );
318+ EXPECT_EQ (result1[1 ], " application/json" );
319+ EXPECT_EQ (result1[2 ], " text/plain" );
320+
321+ // With quality values
322+ std::vector<std::string> result2;
323+ EXPECT_TRUE (detail::parse_accept_header (
324+ " text/html;q=0.9,application/json;q=1.0,text/plain;q=0.8" , result2));
325+ EXPECT_EQ (result2.size (), 3 );
326+ EXPECT_EQ (result2[0 ], " application/json" ); // highest q value
327+ EXPECT_EQ (result2[1 ], " text/html" );
328+ EXPECT_EQ (result2[2 ], " text/plain" ); // lowest q value
329+ }
330+
331+ TEST (ParseAcceptHeaderTest, MixedQualityValues) {
332+ // Mixed with and without quality values
333+ std::vector<std::string> result;
334+ EXPECT_TRUE (detail::parse_accept_header (
335+ " text/html,application/json;q=0.5,text/plain;q=0.8" , result));
336+ EXPECT_EQ (result.size (), 3 );
337+ EXPECT_EQ (result[0 ], " text/html" ); // no q value means 1.0
338+ EXPECT_EQ (result[1 ], " text/plain" ); // q=0.8
339+ EXPECT_EQ (result[2 ], " application/json" ); // q=0.5
340+ }
341+
342+ TEST (ParseAcceptHeaderTest, EdgeCases) {
343+ // Empty header
344+ std::vector<std::string> empty_result;
345+ EXPECT_TRUE (detail::parse_accept_header (" " , empty_result));
346+ EXPECT_TRUE (empty_result.empty ());
347+
348+ // Single type
349+ std::vector<std::string> single_result;
350+ EXPECT_TRUE (detail::parse_accept_header (" application/json" , single_result));
351+ EXPECT_EQ (single_result.size (), 1 );
352+ EXPECT_EQ (single_result[0 ], " application/json" );
353+
354+ // Wildcard types
355+ std::vector<std::string> wildcard_result;
356+ EXPECT_TRUE (detail::parse_accept_header (
357+ " text/*;q=0.5,*/*;q=0.1,application/json" , wildcard_result));
358+ EXPECT_EQ (wildcard_result.size (), 3 );
359+ EXPECT_EQ (wildcard_result[0 ], " application/json" );
360+ EXPECT_EQ (wildcard_result[1 ], " text/*" );
361+ EXPECT_EQ (wildcard_result[2 ], " */*" );
362+ }
363+
364+ TEST (ParseAcceptHeaderTest, RealWorldExamples) {
365+ // Common browser Accept header
366+ std::vector<std::string> browser_result;
367+ EXPECT_TRUE (
368+ detail::parse_accept_header (" text/html,application/xhtml+xml,application/"
369+ " xml;q=0.9,image/webp,image/apng,*/*;q=0.8" ,
370+ browser_result));
371+ EXPECT_EQ (browser_result.size (), 6 );
372+ EXPECT_EQ (browser_result[0 ], " text/html" ); // q=1.0 (default)
373+ EXPECT_EQ (browser_result[1 ], " application/xhtml+xml" ); // q=1.0 (default)
374+ EXPECT_EQ (browser_result[2 ], " image/webp" ); // q=1.0 (default)
375+ EXPECT_EQ (browser_result[3 ], " image/apng" ); // q=1.0 (default)
376+ EXPECT_EQ (browser_result[4 ], " application/xml" ); // q=0.9
377+ EXPECT_EQ (browser_result[5 ], " */*" ); // q=0.8
378+
379+ // API client header
380+ std::vector<std::string> api_result;
381+ EXPECT_TRUE (detail::parse_accept_header (
382+ " application/json;q=0.9,application/xml;q=0.8,text/plain;q=0.1" ,
383+ api_result));
384+ EXPECT_EQ (api_result.size (), 3 );
385+ EXPECT_EQ (api_result[0 ], " application/json" );
386+ EXPECT_EQ (api_result[1 ], " application/xml" );
387+ EXPECT_EQ (api_result[2 ], " text/plain" );
388+ }
389+
390+ TEST (ParseAcceptHeaderTest, SpecialCases) {
391+ // Quality value with 3 decimal places
392+ std::vector<std::string> decimal_result;
393+ EXPECT_TRUE (detail::parse_accept_header (
394+ " text/html;q=0.123,application/json;q=0.456" , decimal_result));
395+ EXPECT_EQ (decimal_result.size (), 2 );
396+ EXPECT_EQ (decimal_result[0 ], " application/json" ); // Higher q value
397+ EXPECT_EQ (decimal_result[1 ], " text/html" );
398+
399+ // Zero quality (should still be included but with lowest priority)
400+ std::vector<std::string> zero_q_result;
401+ EXPECT_TRUE (detail::parse_accept_header (" text/html;q=0,application/json;q=1" ,
402+ zero_q_result));
403+ EXPECT_EQ (zero_q_result.size (), 2 );
404+ EXPECT_EQ (zero_q_result[0 ], " application/json" ); // q=1
405+ EXPECT_EQ (zero_q_result[1 ], " text/html" ); // q=0
406+
407+ // No spaces around commas
408+ std::vector<std::string> no_space_result;
409+ EXPECT_TRUE (detail::parse_accept_header (
410+ " text/html;q=0.9,application/json;q=0.8,text/plain;q=0.7" ,
411+ no_space_result));
412+ EXPECT_EQ (no_space_result.size (), 3 );
413+ EXPECT_EQ (no_space_result[0 ], " text/html" );
414+ EXPECT_EQ (no_space_result[1 ], " application/json" );
415+ EXPECT_EQ (no_space_result[2 ], " text/plain" );
416+ }
417+
418+ TEST (ParseAcceptHeaderTest, InvalidCases) {
419+ std::vector<std::string> result;
420+
421+ // Invalid quality value (> 1.0)
422+ EXPECT_FALSE (
423+ detail::parse_accept_header (" text/html;q=1.5,application/json" , result));
424+
425+ // Invalid quality value (< 0.0)
426+ EXPECT_FALSE (
427+ detail::parse_accept_header (" text/html;q=-0.1,application/json" , result));
428+
429+ // Invalid quality value (not a number)
430+ EXPECT_FALSE (detail::parse_accept_header (
431+ " text/html;q=invalid,application/json" , result));
432+
433+ // Empty quality value
434+ EXPECT_FALSE (
435+ detail::parse_accept_header (" text/html;q=,application/json" , result));
436+
437+ // Invalid media type format (no slash and not wildcard)
438+ EXPECT_FALSE (
439+ detail::parse_accept_header (" invalidtype,application/json" , result));
440+
441+ // Empty media type
442+ result.clear ();
443+ EXPECT_FALSE (detail::parse_accept_header (" ,application/json" , result));
444+
445+ // Only commas
446+ result.clear ();
447+ EXPECT_FALSE (detail::parse_accept_header (" ,,," , result));
448+
449+ // Valid cases should still work
450+ EXPECT_TRUE (detail::parse_accept_header (" */*" , result));
451+ EXPECT_EQ (result.size (), 1 );
452+ EXPECT_EQ (result[0 ], " */*" );
453+
454+ EXPECT_TRUE (detail::parse_accept_header (" *" , result));
455+ EXPECT_EQ (result.size (), 1 );
456+ EXPECT_EQ (result[0 ], " *" );
457+
458+ EXPECT_TRUE (detail::parse_accept_header (" text/*" , result));
459+ EXPECT_EQ (result.size (), 1 );
460+ EXPECT_EQ (result[0 ], " text/*" );
461+ }
462+
463+ TEST (ParseAcceptHeaderTest, ContentTypesPopulatedAndInvalidHeaderHandling) {
464+ Server svr;
465+
466+ svr.Get (" /accept_ok" , [&](const Request &req, Response &res) {
467+ EXPECT_EQ (req.accept_content_types .size (), 3 );
468+ EXPECT_EQ (req.accept_content_types [0 ], " application/json" );
469+ EXPECT_EQ (req.accept_content_types [1 ], " text/html" );
470+ EXPECT_EQ (req.accept_content_types [2 ], " */*" );
471+ res.set_content (" ok" , " text/plain" );
472+ });
473+
474+ svr.Get (" /accept_bad_request" , [&](const Request &req, Response &res) {
475+ EXPECT_TRUE (false );
476+ res.set_content (" bad request" , " text/plain" );
477+ });
478+
479+ auto listen_thread = std::thread ([&svr]() { svr.listen (" localhost" , PORT); });
480+ auto se = detail::scope_exit ([&] {
481+ svr.stop ();
482+ listen_thread.join ();
483+ ASSERT_FALSE (svr.is_running ());
484+ });
485+
486+ svr.wait_until_ready ();
487+
488+ Client cli (" localhost" , PORT);
489+
490+ {
491+ auto res =
492+ cli.Get (" /accept_ok" ,
493+ {{" Accept" , " application/json, text/html;q=0.8, */*;q=0.1" }});
494+ ASSERT_TRUE (res);
495+ EXPECT_EQ (StatusCode::OK_200, res->status );
496+ }
497+
498+ {
499+ auto res = cli.Get (" /accept_bad_request" ,
500+ {{" Accept" , " text/html;q=abc,application/json" }});
501+ ASSERT_TRUE (res);
502+ EXPECT_EQ (StatusCode::BadRequest_400, res->status );
503+ }
504+ }
505+
311506TEST (DivideTest, DivideStringTests) {
312507 auto divide = [](const std::string &str, char d) {
313508 std::string lhs;
0 commit comments