1 #include <iostream>
2 #include <string>
3 
4 #include <restinio/all.hpp>
5 
6 using namespace std::string_literals;
7 
8 // Type of query-string parser.
9 using query_string_parser_type =
10 	restinio::expected_t<
11 		restinio::query_string_params_t,
12 		restinio::parse_query_failure_t >
13 	(*)( restinio::string_view_t );
14 
15 // Create an appropriate query-string parser.
create_parser(int argc,char ** argv)16 query_string_parser_type create_parser( int argc, char ** argv )
17 {
18 	if( argc < 2 || "restinio_defaults"s == argv[ 1 ] )
19 		return []( restinio::string_view_t what ) {
20 			return restinio::try_parse_query<
21 				restinio::parse_query_traits::restinio_defaults >( what );
22 		};
23 
24 	if( 2 == argc )
25 	{
26 		if( "javascript_compatible"s == argv[ 1 ] )
27 			return []( restinio::string_view_t what ) {
28 				return restinio::try_parse_query<
29 					restinio::parse_query_traits::javascript_compatible >( what );
30 			};
31 		if( "x_www_form_urlencoded"s == argv[ 1 ] )
32 			return []( restinio::string_view_t what ) {
33 				return restinio::try_parse_query<
34 					restinio::parse_query_traits::x_www_form_urlencoded >( what );
35 			};
36 		if( "relaxed"s == argv[ 1 ] ) {
37 			return []( restinio::string_view_t what ) {
38 				return restinio::try_parse_query<
39 					restinio::parse_query_traits::relaxed >( what );
40 			};
41 		}
42 	}
43 
44 	throw std::runtime_error{
45 			"one optional argument expected: "
46 			"restinio_defaults, javascript_compatible, x_www_form_urlencoded or "
47 			"relaxed"
48 		};
49 }
50 
51 // Create request handler.
handler(const restinio::request_handle_t & req,query_string_parser_type parser)52 restinio::request_handling_status_t handler(
53 	const restinio::request_handle_t& req,
54 	query_string_parser_type parser )
55 {
56 	if( restinio::http_method_get() == req->header().method() )
57 	{
58 		fmt::basic_memory_buffer< char, 1u > response_body;
59 		fmt::format_to( response_body, "GET request to '{}'\n",
60 				req->header().request_target() );
61 
62 		// Request header fields.
63 		fmt::format_to( response_body, "HTTP-fields ({}):\n",
64 				req->header().fields_count() );
65 		for( const auto & f : req->header() )
66 		{
67 			fmt::format_to( response_body, "{}: {}\n",
68 					f.name(), f.value() );
69 		}
70 
71 		// An attempt to parse query-string.
72 		const auto qs_parse_result = parser( req->header().query() );
73 		if( !qs_parse_result )
74 		{
75 			// Return a negative response.
76 			req->create_response( restinio::status_bad_request() )
77 				.append_header( restinio::http_field::server, "RESTinio query string params server" )
78 				.append_header_date_field()
79 				.append_header( restinio::http_field::content_type, "text/plain; charset=utf-8" )
80 				.set_body( "Unable to parse query-string: " +
81 						qs_parse_result.error().description() )
82 				.done();
83 
84 			return restinio::request_accepted();
85 		}
86 
87 		// Handle query-string params.
88 		const auto & qp = *qs_parse_result;
89 		if( qp.empty() )
90 		{
91 			fmt::format_to( response_body, "No query parameters." );
92 		}
93 		else
94 		{
95 			fmt::format_to( response_body, "Query params ({}):\n", qp.size() );
96 
97 			for( const auto p : qp )
98 			{
99 				fmt::format_to( response_body, "'{}' => '{}'\n",
100 						p.first, p.second );
101 			}
102 		}
103 
104 		if( qp.has( "debug" ) && qp[ "debug" ] == "true" )
105 		{
106 			std::cout.write( response_body.data(), response_body.size() );
107 			std::cout << std::flush;
108 		}
109 
110 		req->create_response()
111 			.append_header( restinio::http_field::server, "RESTinio query string params server" )
112 			.append_header_date_field()
113 			.append_header( restinio::http_field::content_type, "text/plain; charset=utf-8" )
114 			.set_body( std::move(response_body) )
115 			.done();
116 
117 		return restinio::request_accepted();
118 	}
119 
120 	return restinio::request_rejected();
121 }
122 
main(int argc,char ** argv)123 int main( int argc, char ** argv )
124 {
125 	try
126 	{
127 		restinio::run(
128 			restinio::on_thread_pool( std::thread::hardware_concurrency() )
129 				.port( 8080 )
130 				.address( "localhost" )
131 				.request_handler(
132 					[parser = create_parser( argc, argv )]( const auto & req ) {
133 						return handler( req, parser );
134 					} )
135 			);
136 	}
137 	catch( const std::exception & ex )
138 	{
139 		std::cerr << "Error: " << ex.what() << std::endl;
140 		return 1;
141 	}
142 
143 	return 0;
144 }
145 
146