1 /*
2 	restinio
3 */
4 
5 /*!
6 	helpers for http communication.
7 */
8 
9 #pragma once
10 
11 #include <restinio/impl/include_fmtlib.hpp>
12 
13 #include <restinio/impl/string_caseless_compare.hpp>
14 
15 #include <restinio/exception.hpp>
16 #include <restinio/string_view.hpp>
17 #include <restinio/optional.hpp>
18 #include <restinio/common_types.hpp>
19 
20 #include <http_parser.h>
21 
22 #include <iosfwd>
23 #include <string>
24 #include <vector>
25 #include <algorithm>
26 
27 namespace restinio
28 {
29 
30 
31 // Adopted header fields
32 // (https://www.iana.org/assignments/message-headers/message-headers.xml#perm-headers).
33 // Fields `Connection` and `Content-Length` are specieal cases, thus they are excluded from the list.
34 #define RESTINIO_HTTP_FIELDS_MAP( RESTINIO_GEN ) \
35 	RESTINIO_GEN( a_im,                         A-IM )                        \
36 	RESTINIO_GEN( accept,                       Accept )                      \
37 	RESTINIO_GEN( accept_additions,             Accept-Additions )            \
38 	RESTINIO_GEN( accept_charset,               Accept-Charset )              \
39 	RESTINIO_GEN( accept_datetime,              Accept-Datetime )             \
40 	RESTINIO_GEN( accept_encoding,              Accept-Encoding )             \
41 	RESTINIO_GEN( accept_features,              Accept-Features )             \
42 	RESTINIO_GEN( accept_language,              Accept-Language )             \
43 	RESTINIO_GEN( accept_patch,                 Accept-Patch )                \
44 	RESTINIO_GEN( accept_post,                  Accept-Post )                 \
45 	RESTINIO_GEN( accept_ranges,                Accept-Ranges )               \
46 	RESTINIO_GEN( age,                          Age )                         \
47 	RESTINIO_GEN( allow,                        Allow )                       \
48 	RESTINIO_GEN( alpn,                         ALPN )                        \
49 	RESTINIO_GEN( alt_svc,                      Alt-Svc )                     \
50 	RESTINIO_GEN( alt_used,                     Alt-Used )                    \
51 	RESTINIO_GEN( alternates,                   Alternates )                  \
52 	RESTINIO_GEN( apply_to_redirect_ref,        Apply-To-Redirect-Ref )       \
53 	RESTINIO_GEN( authentication_control,       Authentication-Control )      \
54 	RESTINIO_GEN( authentication_info,          Authentication-Info )         \
55 	RESTINIO_GEN( authorization,                Authorization )               \
56 	RESTINIO_GEN( c_ext,                        C-Ext )                       \
57 	RESTINIO_GEN( c_man,                        C-Man )                       \
58 	RESTINIO_GEN( c_opt,                        C-Opt )                       \
59 	RESTINIO_GEN( c_pep,                        C-PEP )                       \
60 	RESTINIO_GEN( c_pep_info,                   C-PEP-Info )                  \
61 	RESTINIO_GEN( cache_control,                Cache-Control )               \
62 	RESTINIO_GEN( caldav_timezones,             CalDAV-Timezones )            \
63 	RESTINIO_GEN( close,                        Close )                       \
64 	RESTINIO_GEN( content_base,                 Content-Base )                \
65 	RESTINIO_GEN( content_disposition,          Content-Disposition )         \
66 	RESTINIO_GEN( content_encoding,             Content-Encoding )            \
67 	RESTINIO_GEN( content_id,                   Content-ID )                  \
68 	RESTINIO_GEN( content_language,             Content-Language )            \
69 	RESTINIO_GEN( content_location,             Content-Location )            \
70 	RESTINIO_GEN( content_md5,                  Content-MD5 )                 \
71 	RESTINIO_GEN( content_range,                Content-Range )               \
72 	RESTINIO_GEN( content_script_type,          Content-Script-Type )         \
73 	RESTINIO_GEN( content_style_type,           Content-Style-Type )          \
74 	RESTINIO_GEN( content_type,                 Content-Type )                \
75 	RESTINIO_GEN( content_version,              Content-Version )             \
76 	RESTINIO_GEN( cookie,                       Cookie )                      \
77 	RESTINIO_GEN( cookie2,                      Cookie2 )                     \
78 	RESTINIO_GEN( dasl,                         DASL )                        \
79 	RESTINIO_GEN( dav,                          DAV )                         \
80 	RESTINIO_GEN( date,                         Date )                        \
81 	RESTINIO_GEN( default_style,                Default-Style )               \
82 	RESTINIO_GEN( delta_base,                   Delta-Base )                  \
83 	RESTINIO_GEN( depth,                        Depth )                       \
84 	RESTINIO_GEN( derived_from,                 Derived-From )                \
85 	RESTINIO_GEN( destination,                  Destination )                 \
86 	RESTINIO_GEN( differential_id,              Differential-ID )             \
87 	RESTINIO_GEN( digest,                       Digest )                      \
88 	RESTINIO_GEN( etag,                         ETag )                        \
89 	RESTINIO_GEN( expect,                       Expect )                      \
90 	RESTINIO_GEN( expires,                      Expires )                     \
91 	RESTINIO_GEN( ext,                          Ext )                         \
92 	RESTINIO_GEN( forwarded,                    Forwarded )                   \
93 	RESTINIO_GEN( from,                         From )                        \
94 	RESTINIO_GEN( getprofile,                   GetProfile )                  \
95 	RESTINIO_GEN( hobareg,                      Hobareg )                     \
96 	RESTINIO_GEN( host,                         Host )                        \
97 	RESTINIO_GEN( http2_settings,               HTTP2-Settings )              \
98 	RESTINIO_GEN( im,                           IM )                          \
99 	RESTINIO_GEN( if_,                          If )                          \
100 	RESTINIO_GEN( if_match,                     If-Match )                    \
101 	RESTINIO_GEN( if_modified_since,            If-Modified-Since )           \
102 	RESTINIO_GEN( if_none_match,                If-None-Match )               \
103 	RESTINIO_GEN( if_range,                     If-Range )                    \
104 	RESTINIO_GEN( if_schedule_tag_match,        If-Schedule-Tag-Match )       \
105 	RESTINIO_GEN( if_unmodified_since,          If-Unmodified-Since )         \
106 	RESTINIO_GEN( keep_alive,                   Keep-Alive )                  \
107 	RESTINIO_GEN( label,                        Label )                       \
108 	RESTINIO_GEN( last_modified,                Last-Modified )               \
109 	RESTINIO_GEN( link,                         Link )                        \
110 	RESTINIO_GEN( location,                     Location )                    \
111 	RESTINIO_GEN( lock_token,                   Lock-Token )                  \
112 	RESTINIO_GEN( man,                          Man )                         \
113 	RESTINIO_GEN( max_forwards,                 Max-Forwards )                \
114 	RESTINIO_GEN( memento_datetime,             Memento-Datetime )            \
115 	RESTINIO_GEN( meter,                        Meter )                       \
116 	RESTINIO_GEN( mime_version,                 MIME-Version )                \
117 	RESTINIO_GEN( negotiate,                    Negotiate )                   \
118 	RESTINIO_GEN( opt,                          Opt )                         \
119 	RESTINIO_GEN( optional_www_authenticate,    Optional-WWW-Authenticate )   \
120 	RESTINIO_GEN( ordering_type,                Ordering-Type )               \
121 	RESTINIO_GEN( origin,                       Origin )                      \
122 	RESTINIO_GEN( overwrite,                    Overwrite )                   \
123 	RESTINIO_GEN( p3p,                          P3P )                         \
124 	RESTINIO_GEN( pep,                          PEP )                         \
125 	RESTINIO_GEN( pics_label,                   PICS-Label )                  \
126 	RESTINIO_GEN( pep_info,                     Pep-Info )                    \
127 	RESTINIO_GEN( position,                     Position )                    \
128 	RESTINIO_GEN( pragma,                       Pragma )                      \
129 	RESTINIO_GEN( prefer,                       Prefer )                      \
130 	RESTINIO_GEN( preference_applied,           Preference-Applied )          \
131 	RESTINIO_GEN( profileobject,                ProfileObject )               \
132 	RESTINIO_GEN( protocol,                     Protocol )                    \
133 	RESTINIO_GEN( protocol_info,                Protocol-Info )               \
134 	RESTINIO_GEN( protocol_query,               Protocol-Query )              \
135 	RESTINIO_GEN( protocol_request,             Protocol-Request )            \
136 	RESTINIO_GEN( proxy_authenticate,           Proxy-Authenticate )          \
137 	RESTINIO_GEN( proxy_authentication_info,    Proxy-Authentication-Info )   \
138 	RESTINIO_GEN( proxy_authorization,          Proxy-Authorization )         \
139 	RESTINIO_GEN( proxy_features,               Proxy-Features )              \
140 	RESTINIO_GEN( proxy_instruction,            Proxy-Instruction )           \
141 	RESTINIO_GEN( public_,                      Public )                      \
142 	RESTINIO_GEN( public_key_pins,              Public-Key-Pins )             \
143 	RESTINIO_GEN( public_key_pins_report_only,  Public-Key-Pins-Report-Only ) \
144 	RESTINIO_GEN( range,                        Range )                       \
145 	RESTINIO_GEN( redirect_ref,                 Redirect-Ref )                \
146 	RESTINIO_GEN( referer,                      Referer )                     \
147 	RESTINIO_GEN( retry_after,                  Retry-After )                 \
148 	RESTINIO_GEN( safe,                         Safe )                        \
149 	RESTINIO_GEN( schedule_reply,               Schedule-Reply )              \
150 	RESTINIO_GEN( schedule_tag,                 Schedule-Tag )                \
151 	RESTINIO_GEN( sec_websocket_accept,         Sec-WebSocket-Accept )        \
152 	RESTINIO_GEN( sec_websocket_extensions,     Sec-WebSocket-Extensions )    \
153 	RESTINIO_GEN( sec_websocket_key,            Sec-WebSocket-Key )           \
154 	RESTINIO_GEN( sec_websocket_protocol,       Sec-WebSocket-Protocol )      \
155 	RESTINIO_GEN( sec_websocket_version,        Sec-WebSocket-Version )       \
156 	RESTINIO_GEN( security_scheme,              Security-Scheme )             \
157 	RESTINIO_GEN( server,                       Server )                      \
158 	RESTINIO_GEN( set_cookie,                   Set-Cookie )                  \
159 	RESTINIO_GEN( set_cookie2,                  Set-Cookie2 )                 \
160 	RESTINIO_GEN( setprofile,                   SetProfile )                  \
161 	RESTINIO_GEN( slug,                         SLUG )                        \
162 	RESTINIO_GEN( soapaction,                   SoapAction )                  \
163 	RESTINIO_GEN( status_uri,                   Status-URI )                  \
164 	RESTINIO_GEN( strict_transport_security,    Strict-Transport-Security )   \
165 	RESTINIO_GEN( surrogate_capability,         Surrogate-Capability )        \
166 	RESTINIO_GEN( surrogate_control,            Surrogate-Control )           \
167 	RESTINIO_GEN( tcn,                          TCN )                         \
168 	RESTINIO_GEN( te,                           TE )                          \
169 	RESTINIO_GEN( timeout,                      Timeout )                     \
170 	RESTINIO_GEN( topic,                        Topic )                       \
171 	RESTINIO_GEN( trailer,                      Trailer )                     \
172 	RESTINIO_GEN( transfer_encoding,            Transfer-Encoding )           \
173 	RESTINIO_GEN( ttl,                          TTL )                         \
174 	RESTINIO_GEN( urgency,                      Urgency )                     \
175 	RESTINIO_GEN( uri,                          URI )                         \
176 	RESTINIO_GEN( upgrade,                      Upgrade )                     \
177 	RESTINIO_GEN( user_agent,                   User-Agent )                  \
178 	RESTINIO_GEN( variant_vary,                 Variant-Vary )                \
179 	RESTINIO_GEN( vary,                         Vary )                        \
180 	RESTINIO_GEN( via,                          Via )                         \
181 	RESTINIO_GEN( www_authenticate,             WWW-Authenticate )            \
182 	RESTINIO_GEN( want_digest,                  Want-Digest )                 \
183 	RESTINIO_GEN( warning,                      Warning )                     \
184 	RESTINIO_GEN( x_frame_options,              X-Frame-Options )             \
185 \
186 	RESTINIO_GEN( access_control,               Access-Control )              \
187 	RESTINIO_GEN( access_control_allow_credentials, Access-Control-Allow-Credentials ) \
188 	RESTINIO_GEN( access_control_allow_headers, Access-Control-Allow-Headers )\
189 	RESTINIO_GEN( access_control_allow_methods, Access-Control-Allow-Methods )\
190 	RESTINIO_GEN( access_control_allow_origin,  Access-Control-Allow-Origin ) \
191 	RESTINIO_GEN( access_control_max_age,       Access-Control-Max-Age )      \
192 	RESTINIO_GEN( access_control_request_method,    Access-Control-Request-Method )    \
193 	RESTINIO_GEN( access_control_request_headers,   Access-Control-Request-Headers )   \
194 	RESTINIO_GEN( compliance,                   Compliance )                  \
195 	RESTINIO_GEN( content_transfer_encoding,    Content-Transfer-Encoding )   \
196 	RESTINIO_GEN( cost,                         Cost )                        \
197 	RESTINIO_GEN( ediint_features,              EDIINT-Features )             \
198 	RESTINIO_GEN( message_id,                   Message-ID )                  \
199 	RESTINIO_GEN( method_check,                 Method-Check )                \
200 	RESTINIO_GEN( method_check_expires,         Method-Check-Expires )        \
201 	RESTINIO_GEN( non_compliance,               Non-Compliance )              \
202 	RESTINIO_GEN( optional,                     Optional )                    \
203 	RESTINIO_GEN( referer_root,                 Referer-Root )                \
204 	RESTINIO_GEN( resolution_hint,              Resolution-Hint )             \
205 	RESTINIO_GEN( resolver_location,            Resolver-Location )           \
206 	RESTINIO_GEN( subok,                        SubOK )                       \
207 	RESTINIO_GEN( subst,                        Subst )                       \
208 	RESTINIO_GEN( title,                        Title )                       \
209 	RESTINIO_GEN( ua_color,                     UA-Color )                    \
210 	RESTINIO_GEN( ua_media,                     UA-Media )                    \
211 	RESTINIO_GEN( ua_pixels,                    UA-Pixels )                   \
212 	RESTINIO_GEN( ua_resolution,                UA-Resolution )               \
213 	RESTINIO_GEN( ua_windowpixels,              UA-Windowpixels )             \
214 	RESTINIO_GEN( version,                      Version )                     \
215 	RESTINIO_GEN( x_device_accept,              X-Device-Accept )             \
216 	RESTINIO_GEN( x_device_accept_charset,      X-Device-Accept-Charset )     \
217 	RESTINIO_GEN( x_device_accept_encoding,     X-Device-Accept-Encoding )    \
218 	RESTINIO_GEN( x_device_accept_language,     X-Device-Accept-Language )    \
219 	RESTINIO_GEN( x_device_user_agent,          X-Device-User-Agent )
220 	// SPECIAL CASE: RESTINIO_GEN( connection,                   Connection )
221 	// SPECIAL CASE: RESTINIO_GEN( content_length,               Content-Length )
222 
223 //
224 // http_field_t
225 //
226 
227 //! C++ enum that repeats nodejs c-style enum.
228 /*!
229 	\note Fields `Connection` and `Content-Length` are specieal cases,
230 	thus they are not present in the list.
231 */
232 enum class http_field_t : std::uint8_t //By now 152 + 34 + 1 items fits to uint8_t
233 {
234 #define RESTINIO_HTTP_FIELD_GEN( name, ignored ) name,
235 	RESTINIO_HTTP_FIELDS_MAP( RESTINIO_HTTP_FIELD_GEN )
236 #undef RESTINIO_HTTP_FIELD_GEN
237 	// Unspecified field.
238 	field_unspecified
239 };
240 
241 //! Helper alies to omitt `_t` suffix.
242 using http_field = http_field_t;
243 
244 //
245 // string_to_field()
246 //
247 
248 //! Helper function to get method string name.
249 //! \{
250 inline http_field_t
string_to_field(string_view_t field)251 string_to_field( string_view_t field ) noexcept
252 {
253 	const char * field_name = field.data();
254 	const std::size_t field_name_size = field.size();
255 
256 #define RESTINIO_HTTP_CHECK_FOR_FIELD( field_id, candidate_field_name ) \
257 	if( impl::is_equal_caseless(field_name, #candidate_field_name , field_name_size ) ) \
258 		return http_field_t:: field_id;
259 
260 	// TODO: make most popular fields to be checked first.
261 
262 	switch( field_name_size )
263 	{
264 		case 2:
265 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_,                          If )
266 			RESTINIO_HTTP_CHECK_FOR_FIELD( im,                           IM )
267 			RESTINIO_HTTP_CHECK_FOR_FIELD( te,                           TE )
268 			break;
269 
270 		case 3:
271 			RESTINIO_HTTP_CHECK_FOR_FIELD( age,                          Age )
272 			RESTINIO_HTTP_CHECK_FOR_FIELD( dav,                          DAV )
273 			RESTINIO_HTTP_CHECK_FOR_FIELD( ext,                          Ext )
274 			RESTINIO_HTTP_CHECK_FOR_FIELD( man,                          Man )
275 			RESTINIO_HTTP_CHECK_FOR_FIELD( opt,                          Opt )
276 			RESTINIO_HTTP_CHECK_FOR_FIELD( p3p,                          P3P )
277 			RESTINIO_HTTP_CHECK_FOR_FIELD( pep,                          PEP )
278 			RESTINIO_HTTP_CHECK_FOR_FIELD( tcn,                          TCN )
279 			RESTINIO_HTTP_CHECK_FOR_FIELD( ttl,                          TTL )
280 			RESTINIO_HTTP_CHECK_FOR_FIELD( uri,                          URI )
281 			RESTINIO_HTTP_CHECK_FOR_FIELD( via,                          Via )
282 			break;
283 
284 		case 4:
285 			// Known to be more used first:
286 			RESTINIO_HTTP_CHECK_FOR_FIELD( host,                         Host )
287 
288 			RESTINIO_HTTP_CHECK_FOR_FIELD( a_im,                         A-IM )
289 			RESTINIO_HTTP_CHECK_FOR_FIELD( alpn,                         ALPN )
290 			RESTINIO_HTTP_CHECK_FOR_FIELD( dasl,                         DASL )
291 			RESTINIO_HTTP_CHECK_FOR_FIELD( date,                         Date )
292 			RESTINIO_HTTP_CHECK_FOR_FIELD( etag,                         ETag )
293 			RESTINIO_HTTP_CHECK_FOR_FIELD( from,                         From )
294 			RESTINIO_HTTP_CHECK_FOR_FIELD( link,                         Link )
295 			RESTINIO_HTTP_CHECK_FOR_FIELD( safe,                         Safe )
296 			RESTINIO_HTTP_CHECK_FOR_FIELD( slug,                         SLUG )
297 			RESTINIO_HTTP_CHECK_FOR_FIELD( vary,                         Vary )
298 			RESTINIO_HTTP_CHECK_FOR_FIELD( cost,                         Cost )
299 			break;
300 
301 		case 5:
302 			RESTINIO_HTTP_CHECK_FOR_FIELD( allow,                        Allow )
303 			RESTINIO_HTTP_CHECK_FOR_FIELD( c_ext,                        C-Ext )
304 			RESTINIO_HTTP_CHECK_FOR_FIELD( c_man,                        C-Man )
305 			RESTINIO_HTTP_CHECK_FOR_FIELD( c_opt,                        C-Opt )
306 			RESTINIO_HTTP_CHECK_FOR_FIELD( c_pep,                        C-PEP )
307 			RESTINIO_HTTP_CHECK_FOR_FIELD( close,                        Close )
308 			RESTINIO_HTTP_CHECK_FOR_FIELD( depth,                        Depth )
309 			RESTINIO_HTTP_CHECK_FOR_FIELD( label,                        Label )
310 			RESTINIO_HTTP_CHECK_FOR_FIELD( meter,                        Meter )
311 			RESTINIO_HTTP_CHECK_FOR_FIELD( range,                        Range )
312 			RESTINIO_HTTP_CHECK_FOR_FIELD( topic,                        Topic )
313 			RESTINIO_HTTP_CHECK_FOR_FIELD( subok,                        SubOK )
314 			RESTINIO_HTTP_CHECK_FOR_FIELD( subst,                        Subst )
315 			RESTINIO_HTTP_CHECK_FOR_FIELD( title,                        Title )
316 			break;
317 
318 		case 6:
319 			// Known to be more used first:
320 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept,                       Accept )
321 			RESTINIO_HTTP_CHECK_FOR_FIELD( cookie,                       Cookie )
322 			RESTINIO_HTTP_CHECK_FOR_FIELD( server,                       Server )
323 
324 			RESTINIO_HTTP_CHECK_FOR_FIELD( digest,                       Digest )
325 			RESTINIO_HTTP_CHECK_FOR_FIELD( expect,                       Expect )
326 			RESTINIO_HTTP_CHECK_FOR_FIELD( origin,                       Origin )
327 			RESTINIO_HTTP_CHECK_FOR_FIELD( pragma,                       Pragma )
328 			RESTINIO_HTTP_CHECK_FOR_FIELD( prefer,                       Prefer )
329 			RESTINIO_HTTP_CHECK_FOR_FIELD( public_,                      Public )
330 			break;
331 
332 		case 7:
333 			RESTINIO_HTTP_CHECK_FOR_FIELD( alt_svc,                      Alt-Svc )
334 			RESTINIO_HTTP_CHECK_FOR_FIELD( cookie2,                      Cookie2 )
335 			RESTINIO_HTTP_CHECK_FOR_FIELD( expires,                      Expires )
336 			RESTINIO_HTTP_CHECK_FOR_FIELD( hobareg,                      Hobareg )
337 			RESTINIO_HTTP_CHECK_FOR_FIELD( referer,                      Referer )
338 			RESTINIO_HTTP_CHECK_FOR_FIELD( timeout,                      Timeout )
339 			RESTINIO_HTTP_CHECK_FOR_FIELD( trailer,                      Trailer )
340 			RESTINIO_HTTP_CHECK_FOR_FIELD( urgency,                      Urgency )
341 			RESTINIO_HTTP_CHECK_FOR_FIELD( upgrade,                      Upgrade )
342 			RESTINIO_HTTP_CHECK_FOR_FIELD( warning,                      Warning )
343 			RESTINIO_HTTP_CHECK_FOR_FIELD( version,                      Version )
344 			break;
345 
346 		case 8:
347 			RESTINIO_HTTP_CHECK_FOR_FIELD( alt_used,                     Alt-Used )
348 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_match,                     If-Match )
349 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_range,                     If-Range )
350 			RESTINIO_HTTP_CHECK_FOR_FIELD( location,                     Location )
351 			RESTINIO_HTTP_CHECK_FOR_FIELD( pep_info,                     Pep-Info )
352 			RESTINIO_HTTP_CHECK_FOR_FIELD( position,                     Position )
353 			RESTINIO_HTTP_CHECK_FOR_FIELD( protocol,                     Protocol )
354 			RESTINIO_HTTP_CHECK_FOR_FIELD( optional,                     Optional )
355 			RESTINIO_HTTP_CHECK_FOR_FIELD( ua_color,                     UA-Color )
356 			RESTINIO_HTTP_CHECK_FOR_FIELD( ua_media,                     UA-Media )
357 			break;
358 
359 		case 9:
360 			RESTINIO_HTTP_CHECK_FOR_FIELD( forwarded,                    Forwarded )
361 			RESTINIO_HTTP_CHECK_FOR_FIELD( negotiate,                    Negotiate )
362 			RESTINIO_HTTP_CHECK_FOR_FIELD( overwrite,                    Overwrite )
363 			RESTINIO_HTTP_CHECK_FOR_FIELD( ua_pixels,                    UA-Pixels )
364 			break;
365 
366 		case 10:
367 			RESTINIO_HTTP_CHECK_FOR_FIELD( alternates,                   Alternates )
368 			RESTINIO_HTTP_CHECK_FOR_FIELD( c_pep_info,                   C-PEP-Info )
369 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_id,                   Content-ID )
370 			RESTINIO_HTTP_CHECK_FOR_FIELD( delta_base,                   Delta-Base )
371 			RESTINIO_HTTP_CHECK_FOR_FIELD( getprofile,                   GetProfile )
372 			RESTINIO_HTTP_CHECK_FOR_FIELD( keep_alive,                   Keep-Alive )
373 			RESTINIO_HTTP_CHECK_FOR_FIELD( lock_token,                   Lock-Token )
374 			RESTINIO_HTTP_CHECK_FOR_FIELD( pics_label,                   PICS-Label )
375 			RESTINIO_HTTP_CHECK_FOR_FIELD( set_cookie,                   Set-Cookie )
376 			RESTINIO_HTTP_CHECK_FOR_FIELD( setprofile,                   SetProfile )
377 			RESTINIO_HTTP_CHECK_FOR_FIELD( soapaction,                   SoapAction )
378 			RESTINIO_HTTP_CHECK_FOR_FIELD( status_uri,                   Status-URI )
379 			RESTINIO_HTTP_CHECK_FOR_FIELD( user_agent,                   User-Agent )
380 			RESTINIO_HTTP_CHECK_FOR_FIELD( compliance,                   Compliance )
381 			RESTINIO_HTTP_CHECK_FOR_FIELD( message_id,                   Message-ID )
382 			break;
383 
384 		case 11:
385 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_post,                  Accept-Post )
386 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_md5,                  Content-MD5 )
387 			RESTINIO_HTTP_CHECK_FOR_FIELD( destination,                  Destination )
388 			RESTINIO_HTTP_CHECK_FOR_FIELD( retry_after,                  Retry-After )
389 			RESTINIO_HTTP_CHECK_FOR_FIELD( set_cookie2,                  Set-Cookie2 )
390 			RESTINIO_HTTP_CHECK_FOR_FIELD( want_digest,                  Want-Digest )
391 			break;
392 
393 		case 12:
394 			// Known to be more used first:
395 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_type,                 Content-Type )
396 
397 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_patch,                 Accept-Patch )
398 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_base,                 Content-Base )
399 			RESTINIO_HTTP_CHECK_FOR_FIELD( derived_from,                 Derived-From )
400 			RESTINIO_HTTP_CHECK_FOR_FIELD( max_forwards,                 Max-Forwards )
401 			RESTINIO_HTTP_CHECK_FOR_FIELD( mime_version,                 MIME-Version )
402 			RESTINIO_HTTP_CHECK_FOR_FIELD( schedule_tag,                 Schedule-Tag )
403 			RESTINIO_HTTP_CHECK_FOR_FIELD( redirect_ref,                 Redirect-Ref )
404 			RESTINIO_HTTP_CHECK_FOR_FIELD( variant_vary,                 Variant-Vary )
405 			RESTINIO_HTTP_CHECK_FOR_FIELD( method_check,                 Method-Check )
406 			RESTINIO_HTTP_CHECK_FOR_FIELD( referer_root,                 Referer-Root )
407 			break;
408 
409 		case 13:
410 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_ranges,                Accept-Ranges )
411 			RESTINIO_HTTP_CHECK_FOR_FIELD( authorization,                Authorization )
412 			RESTINIO_HTTP_CHECK_FOR_FIELD( cache_control,                Cache-Control )
413 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_range,                Content-Range )
414 			RESTINIO_HTTP_CHECK_FOR_FIELD( default_style,                Default-Style )
415 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_none_match,                If-None-Match )
416 			RESTINIO_HTTP_CHECK_FOR_FIELD( last_modified,                Last-Modified )
417 			RESTINIO_HTTP_CHECK_FOR_FIELD( ordering_type,                Ordering-Type )
418 			RESTINIO_HTTP_CHECK_FOR_FIELD( profileobject,                ProfileObject )
419 			RESTINIO_HTTP_CHECK_FOR_FIELD( protocol_info,                Protocol-Info )
420 			RESTINIO_HTTP_CHECK_FOR_FIELD( ua_resolution,                UA-Resolution )
421 			break;
422 
423 		case 14:
424 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_charset,               Accept-Charset )
425 			RESTINIO_HTTP_CHECK_FOR_FIELD( http2_settings,               HTTP2-Settings )
426 			RESTINIO_HTTP_CHECK_FOR_FIELD( protocol_query,               Protocol-Query )
427 			RESTINIO_HTTP_CHECK_FOR_FIELD( proxy_features,               Proxy-Features )
428 			RESTINIO_HTTP_CHECK_FOR_FIELD( schedule_reply,               Schedule-Reply )
429 			RESTINIO_HTTP_CHECK_FOR_FIELD( non_compliance,               Non-Compliance )
430 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control,               Access-Control )
431 			break;
432 
433 		case 15:
434 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_encoding,              Accept-Encoding )
435 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_features,              Accept-Features )
436 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_language,              Accept-Language )
437 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_datetime,              Accept-Datetime )
438 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_version,              Content-Version )
439 			RESTINIO_HTTP_CHECK_FOR_FIELD( differential_id,              Differential-ID )
440 			RESTINIO_HTTP_CHECK_FOR_FIELD( public_key_pins,              Public-Key-Pins )
441 			RESTINIO_HTTP_CHECK_FOR_FIELD( security_scheme,              Security-Scheme )
442 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_frame_options,              X-Frame-Options )
443 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_device_accept,              X-Device-Accept )
444 			RESTINIO_HTTP_CHECK_FOR_FIELD( resolution_hint,              Resolution-Hint )
445 			RESTINIO_HTTP_CHECK_FOR_FIELD( ediint_features,              EDIINT-Features )
446 			RESTINIO_HTTP_CHECK_FOR_FIELD( ua_windowpixels,              UA-Windowpixels )
447 			break;
448 
449 		case 16:
450 			RESTINIO_HTTP_CHECK_FOR_FIELD( accept_additions,             Accept-Additions )
451 			RESTINIO_HTTP_CHECK_FOR_FIELD( caldav_timezones,             CalDAV-Timezones )
452 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_encoding,             Content-Encoding )
453 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_language,             Content-Language )
454 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_location,             Content-Location )
455 			RESTINIO_HTTP_CHECK_FOR_FIELD( memento_datetime,             Memento-Datetime )
456 			RESTINIO_HTTP_CHECK_FOR_FIELD( protocol_request,             Protocol-Request )
457 			RESTINIO_HTTP_CHECK_FOR_FIELD( www_authenticate,             WWW-Authenticate )
458 			break;
459 
460 		case 17:
461 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_modified_since,            If-Modified-Since )
462 			RESTINIO_HTTP_CHECK_FOR_FIELD( proxy_instruction,            Proxy-Instruction )
463 			RESTINIO_HTTP_CHECK_FOR_FIELD( sec_websocket_key,            Sec-WebSocket-Key )
464 			RESTINIO_HTTP_CHECK_FOR_FIELD( surrogate_control,            Surrogate-Control )
465 			RESTINIO_HTTP_CHECK_FOR_FIELD( transfer_encoding,            Transfer-Encoding )
466 			RESTINIO_HTTP_CHECK_FOR_FIELD( resolver_location,            Resolver-Location )
467 			break;
468 
469 		case 18:
470 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_style_type,           Content-Style-Type )
471 			RESTINIO_HTTP_CHECK_FOR_FIELD( preference_applied,           Preference-Applied )
472 			RESTINIO_HTTP_CHECK_FOR_FIELD( proxy_authenticate,           Proxy-Authenticate )
473 			break;
474 
475 		case 19:
476 			RESTINIO_HTTP_CHECK_FOR_FIELD( authentication_info,          Authentication-Info )
477 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_disposition,          Content-Disposition )
478 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_script_type,          Content-Script-Type )
479 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_unmodified_since,          If-Unmodified-Since )
480 			RESTINIO_HTTP_CHECK_FOR_FIELD( proxy_authorization,          Proxy-Authorization )
481 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_device_user_agent,          X-Device-User-Agent )
482 			break;
483 
484 		case 20:
485 			RESTINIO_HTTP_CHECK_FOR_FIELD( sec_websocket_accept,         Sec-WebSocket-Accept )
486 			RESTINIO_HTTP_CHECK_FOR_FIELD( surrogate_capability,         Surrogate-Capability )
487 			RESTINIO_HTTP_CHECK_FOR_FIELD( method_check_expires,         Method-Check-Expires )
488 			break;
489 
490 		case 21:
491 			RESTINIO_HTTP_CHECK_FOR_FIELD( apply_to_redirect_ref,        Apply-To-Redirect-Ref )
492 			RESTINIO_HTTP_CHECK_FOR_FIELD( if_schedule_tag_match,        If-Schedule-Tag-Match )
493 			RESTINIO_HTTP_CHECK_FOR_FIELD( sec_websocket_version,        Sec-WebSocket-Version )
494 			break;
495 
496 		case 22:
497 			RESTINIO_HTTP_CHECK_FOR_FIELD( authentication_control,       Authentication-Control )
498 			RESTINIO_HTTP_CHECK_FOR_FIELD( sec_websocket_protocol,       Sec-WebSocket-Protocol )
499 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_max_age,       Access-Control-Max-Age )
500 			break;
501 
502 		case 23:
503 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_device_accept_charset,      X-Device-Accept-Charset )
504 			break;
505 
506 		case 24:
507 			RESTINIO_HTTP_CHECK_FOR_FIELD( sec_websocket_extensions,     Sec-WebSocket-Extensions )
508 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_device_accept_encoding,     X-Device-Accept-Encoding )
509 			RESTINIO_HTTP_CHECK_FOR_FIELD( x_device_accept_language,     X-Device-Accept-Language )
510 			break;
511 
512 		case 25:
513 			RESTINIO_HTTP_CHECK_FOR_FIELD( optional_www_authenticate,    Optional-WWW-Authenticate )
514 			RESTINIO_HTTP_CHECK_FOR_FIELD( proxy_authentication_info,    Proxy-Authentication-Info )
515 			RESTINIO_HTTP_CHECK_FOR_FIELD( strict_transport_security,    Strict-Transport-Security )
516 			RESTINIO_HTTP_CHECK_FOR_FIELD( content_transfer_encoding,    Content-Transfer-Encoding )
517 			break;
518 
519 		case 27:
520 			RESTINIO_HTTP_CHECK_FOR_FIELD( public_key_pins_report_only,  Public-Key-Pins-Report-Only )
521 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_allow_origin,  Access-Control-Allow-Origin )
522 			break;
523 
524 		case 28:
525 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_allow_headers, Access-Control-Allow-Headers )
526 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_allow_methods, Access-Control-Allow-Methods )
527 			break;
528 
529 		case 29:
530 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_request_method,    Access-Control-Request-Method )
531 			break;
532 
533 		case 30:
534 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_request_headers,   Access-Control-Request-Headers )
535 			break;
536 
537 		case 32:
538 			RESTINIO_HTTP_CHECK_FOR_FIELD( access_control_allow_credentials, Access-Control-Allow-Credentials )
539 			break;
540 	}
541 
542 #undef RESTINIO_HTTP_CHECK_FOR_FIELD
543 
544 	return http_field_t::field_unspecified;
545 }
546 
547 //
548 // field_to_string()
549 //
550 
551 //! Helper sunction to get method string name.
552 inline const char *
field_to_string(http_field_t f)553 field_to_string( http_field_t f ) noexcept
554 {
555 	const char * result = "";
556 	switch( f )
557 	{
558 		#define RESTINIO_HTTP_FIELD_STR_GEN( name, string_name ) \
559 			case http_field_t::name: result = #string_name; break;
560 
561 			RESTINIO_HTTP_FIELDS_MAP( RESTINIO_HTTP_FIELD_STR_GEN )
562 		#undef RESTINIO_HTTP_FIELD_STR_GEN
563 
564 		case http_field_t::field_unspecified: break; // Ignore.
565 	}
566 
567 	return result;
568 }
569 
570 //
571 // http_header_field_t
572 //
573 
574 //! A single header field.
575 /*!
576 	Fields m_name and m_field_id are kind of having the same meaning,
577 	and m_name field seems like can be omitted, but
578 	for the cases of custom header fields it is important to
579 	rely on the name only. And as the names of almoust all speified fields
580 	fits in SSO it doesn't involve much overhead on standard fields.
581 */
582 class http_header_field_t
583 {
584 	public:
http_header_field_t()585 		http_header_field_t()
586 			:	m_field_id{ http_field_t::field_unspecified }
587 		{}
588 
http_header_field_t(std::string name,std::string value)589 		http_header_field_t(
590 			std::string name,
591 			std::string value )
592 			:	m_name{ std::move( name ) }
593 			,	m_value{ std::move( value ) }
594 			,	m_field_id{ string_to_field( m_name ) }
595 		{}
596 
http_header_field_t(string_view_t name,string_view_t value)597 		http_header_field_t(
598 			string_view_t name,
599 			string_view_t value )
600 			:	m_name{ name.data(), name.size() }
601 			,	m_value{ value.data(), value.size() }
602 			,	m_field_id{ string_to_field( m_name ) }
603 		{}
604 
http_header_field_t(http_field_t field_id,std::string value)605 		http_header_field_t(
606 			http_field_t field_id,
607 			std::string value )
608 			:	m_name{ field_to_string( field_id ) }
609 			,	m_value{ std::move( value ) }
610 			,	m_field_id{ field_id }
611 		{}
612 
http_header_field_t(http_field_t field_id,string_view_t value)613 		http_header_field_t(
614 			http_field_t field_id,
615 			string_view_t value )
616 			:	m_name{ field_to_string( field_id ) }
617 			,	m_value{ std::move( value ) }
618 			,	m_field_id{ field_id }
619 		{}
620 
name() const621 		const std::string & name() const noexcept { return m_name; }
value() const622 		const std::string & value() const noexcept { return m_value; }
field_id() const623 		http_field_t field_id() const noexcept { return m_field_id; }
624 
625 		void
name(std::string n)626 		name( std::string n )
627 		{
628 			m_name = std::move( n );
629 			m_field_id = string_to_field( m_name );
630 		}
631 
632 		void
value(std::string v)633 		value( std::string v )
634 		{
635 			m_value = std::move( v );
636 		}
637 
638 		void
append_value(string_view_t v)639 		append_value( string_view_t v )
640 		{
641 			m_value.append( v.data(), v.size() );
642 		}
643 
644 		void
field_id(http_field_t field_id)645 		field_id( http_field_t field_id )
646 		{
647 			m_field_id = field_id;
648 			m_name = field_to_string( m_field_id );
649 		}
650 
651 	private:
652 		std::string m_name;
653 		std::string m_value;
654 		http_field_t m_field_id;
655 };
656 
657 // Make neccessary forward declarations.
658 class http_header_fields_t;
659 namespace impl
660 {
661 
662 void
663 append_last_field_accessor( http_header_fields_t &, string_view_t );
664 
665 } /* namespace impl */
666 
667 #if !defined( RESTINIO_HEADER_FIELDS_DEFAULT_RESERVE_COUNT )
668 	#define RESTINIO_HEADER_FIELDS_DEFAULT_RESERVE_COUNT 4
669 #endif
670 
671 //
672 // http_header_fields_t
673 //
674 
675 //! Header fields map.
676 /*!
677 	This class holds a collection of header fields.
678 
679 	There are 2 special cases for fields: `Connection` and `Content-Length`
680 	This cases are handled separetely from the rest of the fields.
681 	And as the implementation of http_header_fields_t doesn't
682 	have checks on each field manipulation checking whether
683 	field name is `Connection` or `Content-Length` it is important
684 	to use proper member functions in derived classes for manipulating them.
685 
686 	@par Getting values of fields
687 
688 	Since v.0.4.9 there are two groups of methods for accessing values of
689 	fields. The first group returns `std::string` (or references/pointers
690 	to `std::string`). This group includes the following methods: get_field(),
691 	get_field_or(), try_get_field().
692 
693 	The second group returns `string_view_t` or `optional_t<string_view_t>`.
694 	This group includes the following methods: value_of() and opt_value_of().
695 
696 	The first group was created in early versions of RESTinio and is present
697 	here for historical and compatibility reasons. They are not deprecated
698 	yet but they could be deprecated in newer versions of RESTinio.
699 	Because of that the usage of value_of() and opt_value_of() is more
700 	preferable.
701 */
702 class http_header_fields_t
703 {
704 		friend void
705 		impl::append_last_field_accessor( http_header_fields_t &, string_view_t );
706 
707 	public:
708 		using fields_container_t = std::vector< http_header_field_t >;
709 
710 		//! Type of const_iterator for enumeration of fields.
711 		using const_iterator = fields_container_t::const_iterator;
712 
713 		//! The result of handling yet another field value.
714 		/*!
715 		 * A value of that enumeration should be returned by a lambda-function
716 		 * passed to for_each_value_of() method.
717 		 *
718 		 * @since v.0.6.9
719 		 */
720 		enum class handling_result_t
721 		{
722 			//! Next value of field should be found and passed to the next
723 			//! invocation of handler.
724 			continue_enumeration,
725 			//! The loop on field values should be stopped.
726 			stop_enumeration
727 		};
728 
continue_enumeration()729 		constexpr static handling_result_t continue_enumeration() noexcept
730 		{ return handling_result_t::continue_enumeration; }
731 
stop_enumeration()732 		constexpr static handling_result_t stop_enumeration() noexcept
733 		{ return handling_result_t::stop_enumeration; }
734 
http_header_fields_t()735 		http_header_fields_t()
736 		{
737 			m_fields.reserve( RESTINIO_HEADER_FIELDS_DEFAULT_RESERVE_COUNT );
738 		}
739 		http_header_fields_t(const http_header_fields_t &) = default;
740 		http_header_fields_t(http_header_fields_t &&) = default;
~http_header_fields_t()741 		virtual ~http_header_fields_t() {}
742 
743 		http_header_fields_t & operator=(const http_header_fields_t &) = default;
744 		http_header_fields_t & operator=(http_header_fields_t &&) = default;
745 
746 		void
swap_fields(http_header_fields_t & http_header_fields)747 		swap_fields( http_header_fields_t & http_header_fields )
748 		{
749 			std::swap( m_fields, http_header_fields.m_fields );
750 		}
751 
752 		//! Check field by name.
753 		bool
has_field(string_view_t field_name) const754 		has_field( string_view_t field_name ) const noexcept
755 		{
756 			return m_fields.cend() != cfind( field_name );
757 		}
758 
759 		//! Check field by field-id.
760 		/*!
761 			\note If `field_id=http_field_t::field_unspecified`
762 			then function returns not more than just a fact
763 			whether there is at least one unspecified field.
764 		*/
765 		bool
has_field(http_field_t field_id) const766 		has_field( http_field_t field_id ) const noexcept
767 		{
768 			return m_fields.cend() != cfind( field_id );
769 		}
770 
771 		//! Set header field via http_header_field_t.
772 		void
set_field(http_header_field_t http_header_field)773 		set_field( http_header_field_t http_header_field )
774 		{
775 			fields_container_t::iterator it;
776 			if( http_field_t::field_unspecified != http_header_field.field_id() )
777 			{
778 				// Field has a standard name.
779 				// Search it by id.
780 				it = find( http_header_field.field_id() );
781 			}
782 			else
783 			{
784 				// Field has a non standard name.
785 				// Search it by name.
786 				it = find( http_header_field.name() );
787 			}
788 
789 			if( m_fields.end() != it )
790 			{
791 				*it = std::move( http_header_field );
792 			}
793 			else
794 			{
795 				m_fields.emplace_back( std::move( http_header_field ) );
796 			}
797 		}
798 
799 		//! Set field with string pair.
800 		void
set_field(std::string field_name,std::string field_value)801 		set_field(
802 			std::string field_name,
803 			std::string field_value )
804 		{
805 			const auto it = find( field_name );
806 
807 			if( m_fields.end() != it )
808 			{
809 				it->name( std::move( field_name ) );
810 				it->value( std::move( field_value ) );
811 			}
812 			else
813 			{
814 				m_fields.emplace_back(
815 					std::move( field_name ),
816 					std::move( field_value ) );
817 			}
818 		}
819 
820 		//! Set field with id-value pair.
821 		/*!
822 			If `field_id=http_field_t::field_unspecified`
823 			then function does nothing.
824 		*/
825 		void
set_field(http_field_t field_id,std::string field_value)826 		set_field(
827 			http_field_t field_id,
828 			std::string field_value )
829 		{
830 			if( http_field_t::field_unspecified != field_id )
831 			{
832 				const auto it = find( field_id );
833 
834 				if( m_fields.end() != it )
835 				{
836 					it->value( std::move( field_value ) );
837 				}
838 				else
839 				{
840 					m_fields.emplace_back(
841 						field_id,
842 						std::move( field_value ) );
843 				}
844 			}
845 		}
846 
847 		/*!
848 		 * @brief Add a field in the form of id-value pair.
849 		 *
850 		 * If `field_id=http_field_t::field_unspecified` then function
851 		 * does nothing.
852 		 *
853 		 * @note
854 		 * This method doesn't check the presence of the field.
855 		 * So it can be used for storing of several values of HTTP-field.
856 		 *
857 		 * @since v.0.6.9
858 		 */
859 		void
add_field(http_field_t field_id,std::string field_value)860 		add_field(
861 			http_field_t field_id,
862 			std::string field_value )
863 		{
864 			if( http_field_t::field_unspecified != field_id )
865 			{
866 				m_fields.emplace_back(
867 					field_id,
868 					std::move( field_value ) );
869 			}
870 		}
871 
872 		/*!
873 		 * @brief Add a field in the form of name-value pair.
874 		 *
875 		 * @note
876 		 * This method doesn't check the presence of the field.
877 		 * So it can be used for storing of several values of HTTP-field.
878 		 *
879 		 * @since v.0.6.9
880 		 */
881 		void
add_field(std::string field_name,std::string field_value)882 		add_field(
883 			std::string field_name,
884 			std::string field_value )
885 		{
886 			m_fields.emplace_back(
887 				std::move( field_name ),
888 				std::move( field_value ) );
889 		}
890 
891 		/*!
892 		 * @brief Add a field in the form of http_header_field object.
893 		 *
894 		 * @note
895 		 * This method doesn't check the presence of the field.
896 		 * So it can be used for storing of several values of HTTP-field.
897 		 *
898 		 * @since v.0.6.9
899 		 */
900 		void
add_field(http_header_field_t http_header_field)901 		add_field( http_header_field_t http_header_field )
902 		{
903 			m_fields.push_back( std::move(http_header_field) );
904 		}
905 
906 		//! Append field with name.
907 		void
append_field(string_view_t field_name,string_view_t field_value)908 		append_field(
909 			string_view_t field_name,
910 			string_view_t field_value )
911 		{
912 			const auto it = find( field_name );
913 
914 			if( m_fields.end() != it )
915 			{
916 				it->append_value( field_value );
917 			}
918 			else
919 			{
920 				m_fields.emplace_back( field_name, field_value );
921 			}
922 		}
923 
924 		//! Append field with id.
925 		/*!
926 			If `field_id=http_field_t::field_unspecified`
927 			then function does nothing.
928 		*/
929 		void
append_field(http_field_t field_id,string_view_t field_value)930 		append_field(
931 			http_field_t field_id,
932 			string_view_t field_value )
933 		{
934 			if( http_field_t::field_unspecified != field_id )
935 			{
936 				const auto it = find( field_id );
937 
938 				if( m_fields.end() != it )
939 				{
940 					it->append_value( field_value );
941 				}
942 				else
943 				{
944 					m_fields.emplace_back( field_id, field_value );
945 				}
946 			}
947 		}
948 
949 		//! Get field by name.
950 		const std::string &
get_field(string_view_t field_name) const951 		get_field( string_view_t field_name ) const
952 		{
953 			const auto it = cfind( field_name );
954 
955 			if( m_fields.end() == it )
956 				throw exception_t{
957 					fmt::format( "field '{}' doesn't exist", field_name ) };
958 
959 			return it->value();
960 		}
961 
962 		//! Try to get the value of a field by field name.
963 		/*!
964 			@note
965 			Returns nullptr if the field is not found.
966 
967 			Usage example:
968 			\code
969 			auto f = headers().try_get_field("Content-Type");
970 			if(f && *f == "text/plain")
971 				...
972 			\endcode
973 		*/
974 		nullable_pointer_t<const std::string>
try_get_field(string_view_t field_name) const975 		try_get_field( string_view_t field_name ) const noexcept
976 		{
977 			const auto it = cfind( field_name );
978 			if( m_fields.end() == it )
979 				return nullptr;
980 			else
981 				return std::addressof(it->value());
982 		}
983 
984 		//! Get field by id.
985 		const std::string &
get_field(http_field_t field_id) const986 		get_field( http_field_t field_id ) const
987 		{
988 			if( http_field_t::field_unspecified == field_id )
989 			{
990 				throw exception_t{
991 					fmt::format(
992 						"unspecified fields cannot be searched by id" ) };
993 			}
994 
995 			const auto it = cfind( field_id );
996 
997 			if( m_fields.end() == it )
998 			{
999 				throw exception_t{
1000 					fmt::format(
1001 						"field '{}' doesn't exist",
1002 						field_to_string( field_id ) ) };
1003 			}
1004 
1005 			return it->value();
1006 		}
1007 
1008 		//! Try to get the value of a field by field ID.
1009 		/*!
1010 			@note
1011 			Returns nullptr if the field is not found.
1012 
1013 			Usage example:
1014 			\code
1015 			auto f = headers().try_get_field(restinio::http_field::content_type);
1016 			if(f && *f == "text/plain")
1017 				...
1018 			\endcode
1019 		*/
1020 		nullable_pointer_t<const std::string>
try_get_field(http_field_t field_id) const1021 		try_get_field( http_field_t field_id ) const noexcept
1022 		{
1023 			if( http_field_t::field_unspecified != field_id )
1024 			{
1025 				const auto it = cfind( field_id );
1026 				if( m_fields.end() != it )
1027 					return std::addressof(it->value());
1028 			}
1029 
1030 			return nullptr;
1031 		}
1032 
1033 		//! Get field value by field name or default value if the field not found.
1034 		/*!
1035 			@note
1036 			This method returns field value as a new std::string instance,
1037 			not a const reference to std::string.
1038 		*/
1039 		std::string
get_field_or(string_view_t field_name,string_view_t default_value) const1040 		get_field_or(
1041 			string_view_t field_name,
1042 			string_view_t default_value ) const
1043 		{
1044 			const auto it = cfind( field_name );
1045 
1046 			if( m_fields.end() == it )
1047 				return std::string( default_value.data(), default_value.size() );
1048 
1049 			return it->value();
1050 		}
1051 
1052 		//! Get field value by field name or default value if the field not found.
1053 		/*!
1054 			@note
1055 			This method returns field value as a new std::string instance,
1056 			not a const reference to std::string.
1057 		*/
1058 		std::string
get_field_or(string_view_t field_name,std::string && default_value) const1059 		get_field_or(
1060 			string_view_t field_name,
1061 			std::string && default_value ) const
1062 		{
1063 			const auto it = cfind( field_name );
1064 
1065 			if( m_fields.end() == it )
1066 				return std::move(default_value);
1067 
1068 			return it->value();
1069 		}
1070 
1071 		//! Get field by name or default value if the field not found.
1072 		/*!
1073 			This is just overload for get_field_or(string_view_t,string_view_t);
1074 		*/
1075 		auto
get_field_or(string_view_t field_name,const char * default_value) const1076 		get_field_or(
1077 			string_view_t field_name,
1078 			const char * default_value ) const
1079 		{
1080 			return this->get_field_or( field_name, string_view_t{ default_value } );
1081 		}
1082 
1083 		//! Get field by name or default value if the field not found.
1084 		/*!
1085 			This is just overload for get_field_or(string_view_t,string_view_t);
1086 		*/
1087 		auto
get_field_or(string_view_t field_name,const std::string & default_value) const1088 		get_field_or(
1089 			string_view_t field_name,
1090 			const std::string & default_value ) const
1091 		{
1092 			return this->get_field_or( field_name, string_view_t{ default_value } );
1093 		}
1094 
1095 		//! Get field by id or default value if the field not found.
1096 		/*!
1097 			@note
1098 			This method returns field value as a new std::string instance,
1099 			not a const reference to std::string.
1100 		*/
1101 		std::string
get_field_or(http_field_t field_id,string_view_t default_value) const1102 		get_field_or(
1103 			http_field_t field_id,
1104 			string_view_t default_value ) const
1105 		{
1106 			if( http_field_t::field_unspecified != field_id )
1107 			{
1108 				const auto it = cfind( field_id );
1109 
1110 				if( m_fields.end() != it )
1111 					return it->value();
1112 			}
1113 
1114 			return std::string( default_value.data(), default_value.size() );
1115 		}
1116 
1117 		//! Get field by id or default value if the field not found.
1118 		/*!
1119 			This is just overload for get_field_or(http_field_t,string_view_t);
1120 		*/
1121 		auto
get_field_or(http_field_t field_id,const char * default_value) const1122 		get_field_or(
1123 			http_field_t field_id,
1124 			const char * default_value ) const
1125 		{
1126 			return this->get_field_or( field_id, string_view_t{ default_value } );
1127 		}
1128 
1129 		//! Get field by id or default value if the field not found.
1130 		/*!
1131 			This is just overload for get_field_or(http_field_t,string_view_t);
1132 		*/
1133 		auto
get_field_or(http_field_t field_id,const std::string & default_value) const1134 		get_field_or(
1135 			http_field_t field_id,
1136 			const std::string & default_value ) const
1137 		{
1138 			return this->get_field_or( field_id, string_view_t{ default_value } );
1139 		}
1140 
1141 		//! Get field by id or default value if the field not found.
1142 		/*!
1143 			@note
1144 			This method returns field value as a new std::string instance,
1145 			not a const reference to std::string.
1146 		*/
1147 		std::string
get_field_or(http_field_t field_id,std::string && default_value) const1148 		get_field_or(
1149 			http_field_t field_id,
1150 			std::string && default_value ) const
1151 		{
1152 			if( http_field_t::field_unspecified != field_id )
1153 			{
1154 				const auto it = cfind( field_id );
1155 
1156 				if( m_fields.end() != it )
1157 					return it->value();
1158 			}
1159 
1160 			return std::move( default_value );
1161 		}
1162 
1163 		//! Remove field by name.
1164 		/*!
1165 		 * If there are several occurences of @a field_name only the first
1166 		 * one will be removed.
1167 		 *
1168 		 * @note
1169 		 * Since v.0.6.9 returns `true` if an occurence of a field
1170 		 * with name @a field_name has been removed. The value `false`
1171 		 * returned if there is no field with name @a field_name.
1172 		 */
1173 		bool
remove_field(string_view_t field_name)1174 		remove_field( string_view_t field_name ) noexcept
1175 		{
1176 			const auto it = find( field_name );
1177 
1178 			if( m_fields.end() != it )
1179 			{
1180 				m_fields.erase( it );
1181 				return true;
1182 			}
1183 
1184 			return false;
1185 		}
1186 
1187 		//! Remove field by id.
1188 		/*!
1189 		 * If there are several occurences of @a field_id only the first
1190 		 * one will be removed.
1191 		 *
1192 		 * @note
1193 		 * Since v.0.6.9 returns `true` if an occurence of a field
1194 		 * with id @a field_id has been removed. The value `false`
1195 		 * returned if there is no field with id @a field_id.
1196 		 */
1197 		bool
remove_field(http_field_t field_id)1198 		remove_field( http_field_t field_id ) noexcept
1199 		{
1200 			if( http_field_t::field_unspecified != field_id )
1201 			{
1202 				const auto it = find( field_id );
1203 
1204 				if( m_fields.end() != it )
1205 				{
1206 					m_fields.erase( it );
1207 					return true;
1208 				}
1209 			}
1210 
1211 			return false;
1212 		}
1213 
1214 		//! Remove all occurences of a field with specified name.
1215 		/*!
1216 		 * @return the count of removed occurences.
1217 		 *
1218 		 * @since v.0.6.9
1219 		 */
1220 		std::size_t
remove_all_of(string_view_t field_name)1221 		remove_all_of( string_view_t field_name ) noexcept
1222 		{
1223 			std::size_t count{};
1224 			for( auto it = m_fields.begin(); it != m_fields.end(); )
1225 			{
1226 				if( impl::is_equal_caseless( it->name(), field_name ) )
1227 				{
1228 					it = m_fields.erase( it );
1229 					++count;
1230 				}
1231 				else
1232 					++it;
1233 			}
1234 
1235 			return count;
1236 		}
1237 
1238 		//! Remove all occurences of a field with specified id.
1239 		/*!
1240 		 * @return the count of removed occurences.
1241 		 *
1242 		 * @since v.0.6.9
1243 		 */
1244 		std::size_t
remove_all_of(http_field_t field_id)1245 		remove_all_of( http_field_t field_id ) noexcept
1246 		{
1247 			std::size_t count{};
1248 			if( http_field_t::field_unspecified != field_id )
1249 			{
1250 				for( auto it = m_fields.begin(); it != m_fields.end(); )
1251 				{
1252 					if( it->field_id() == field_id )
1253 					{
1254 						it = m_fields.erase( it );
1255 						++count;
1256 					}
1257 					else
1258 						++it;
1259 				}
1260 			}
1261 
1262 			return count;
1263 		}
1264 
1265 		/*!
1266 		 * @name Getters of field value which return string_view.
1267 		 * @{
1268 		 */
1269 		//! Get the value of a field or throw if the field not found.
1270 		string_view_t
value_of(string_view_t name) const1271 		value_of(
1272 			//! Name of a field.
1273 			string_view_t name ) const
1274 		{
1275 			return { this->get_field(name) };
1276 		}
1277 
1278 		//! Get the value of a field or throw if the field not found.
1279 		string_view_t
value_of(http_field_t field_id) const1280 		value_of(
1281 			//! ID of a field.
1282 			http_field_t field_id ) const
1283 		{
1284 			return { this->get_field(field_id) };
1285 		}
1286 
1287 		//! Get optional value of a field.
1288 		/*!
1289 			Doesn't throw exception if the field is not found. Empty optional
1290 			will be returned instead.
1291 
1292 			Usage example:
1293 			\code
1294 			auto f = headers().opt_value_of("Content-Type");
1295 			if(f && *f == "text/plain")
1296 				...
1297 			\endcode
1298 		*/
1299 		optional_t< string_view_t >
opt_value_of(string_view_t name) const1300 		opt_value_of(
1301 			//! Name of a field.
1302 			string_view_t name ) const noexcept
1303 		{
1304 			optional_t< string_view_t > result;
1305 
1306 			if( auto * ptr = this->try_get_field(name) )
1307 				result = string_view_t{ *ptr };
1308 
1309 			return result;
1310 		}
1311 
1312 		//! Get optional value of a field.
1313 		/*!
1314 			Doesn't throw exception if the field is not found. Empty optional
1315 			will be returned instead.
1316 
1317 			Usage example:
1318 			\code
1319 			auto f = headers().opt_value_of(restinio::http_field::content_type);
1320 			if(f && *f == "text/plain")
1321 				...
1322 			\endcode
1323 		*/
1324 		optional_t< string_view_t >
opt_value_of(http_field_t field_id) const1325 		opt_value_of(
1326 			//! ID of a field.
1327 			http_field_t field_id ) const noexcept
1328 		{
1329 			optional_t< string_view_t > result;
1330 
1331 			if( auto * ptr = this->try_get_field(field_id) )
1332 				result = string_view_t{ *ptr };
1333 
1334 			return result;
1335 		}
1336 		/*!
1337 		 * @}
1338 		 */
1339 
1340 		//! Enumeration of fields.
1341 		/*!
1342 			Calls \a lambda for each field in the container.
1343 
1344 			Lambda should have one of the following formats:
1345 			\code
1346 			void(const http_header_field_t &);
1347 			void(http_header_field_t);
1348 			\endcode
1349 
1350 			This method is `noexcept` if \a lambda is `noexcept`.
1351 
1352 			Usage example:
1353 			\code
1354 			headers().for_each_field( [](const auto & f) {
1355 				std::cout << f.name() << ": " << f.value() << std::endl;
1356 			} );
1357 			\endcode
1358 		*/
1359 		template< typename Lambda >
1360 		void
for_each_field(Lambda && lambda) const1361 		for_each_field( Lambda && lambda ) const
1362 				noexcept(noexcept(lambda(
1363 						std::declval<const http_header_field_t &>())))
1364 		{
1365 			for( const auto & f : m_fields )
1366 				lambda( f );
1367 		}
1368 
1369 		//! Enumeration of each value of a field.
1370 		/*!
1371 		 * Calls @a lambda for each value of a field @a field_id.
1372 		 *
1373 		 * Lambda should has one of the following formats:
1374 		 * @code
1375 		 * restinio::http_header_fields_t::handling_result_t
1376 		 * (const restinio::string_view_t &);
1377 		 *
1378 		 * restinio::http_header_fields_t::handling_result_t
1379 		 * (restinio::string_view_t);
1380 		 * @endcode
1381 		 *
1382 		 * @note
1383 		 * The @a lambda can throw.
1384 		 *
1385 		 * @attention
1386 		 * The content of this http_header_fields_t shouldn't be changed
1387 		 * during the enumeration (it means that fields can't be removed and
1388 		 * new fields can't be added).
1389 		 *
1390 		 * Usage example:
1391 		 * @code
1392 		 * headers().for_each_value_of(restinio::http_field_t::transfer_encoding,
1393 		 * 		[](auto value) {
1394 		 * 			std::cout << "encoding: " << value << std::endl;
1395 		 * 			return restinio::http_header_fields_t::continue_enumeration();
1396 		 * 		} );
1397 		 * @endcode
1398 		 */
1399 		template< typename Lambda >
1400 		void
for_each_value_of(http_field_t field_id,Lambda && lambda) const1401 		for_each_value_of(
1402 			http_field_t field_id,
1403 			Lambda && lambda ) const
1404 				noexcept(noexcept(lambda(
1405 						std::declval<const string_view_t &>())))
1406 		{
1407 			static_assert(
1408 				std::is_same<
1409 					handling_result_t,
1410 					decltype(lambda(std::declval<const string_view_t &>()))
1411 				>::value,
1412 				"lambda should return restinio::http_header_fields_t::handling_result_t" );
1413 
1414 			for( const auto & f : m_fields )
1415 			{
1416 				if( field_id == f.field_id() )
1417 				{
1418 					const handling_result_t r = lambda( f.value() );
1419 					if( stop_enumeration() == r )
1420 						break;
1421 				}
1422 			}
1423 		}
1424 
1425 		//! Enumeration of each value of a field.
1426 		/*!
1427 		 * Calls @a lambda for each value of a field @a field_name.
1428 		 *
1429 		 * Lambda should has one of the following formats:
1430 		 * @code
1431 		 * restinio::http_header_fields_t::handling_result_t
1432 		 * (const restinio::string_view_t &);
1433 		 *
1434 		 * restinio::http_header_fields_t::handling_result_t
1435 		 * (restinio::string_view_t);
1436 		 * @endcode
1437 		 *
1438 		 * @note
1439 		 * The @a lambda can throw.
1440 		 *
1441 		 * @attention
1442 		 * The content of this http_header_fields_t shouldn't be changed
1443 		 * during the enumeration (it means that fields can't be removed and
1444 		 * new fields can't be added).
1445 		 *
1446 		 * Usage example:
1447 		 * @code
1448 		 * headers().for_each_value_of("Transfer-Encoding",
1449 		 * 		[](auto value) {
1450 		 * 			std::cout << "encoding: " << value << std::endl;
1451 		 * 			return restinio::http_header_fields_t::continue_enumeration();
1452 		 * 		} );
1453 		 * @endcode
1454 		 */
1455 		template< typename Lambda >
1456 		void
for_each_value_of(string_view_t field_name,Lambda && lambda) const1457 		for_each_value_of(
1458 			string_view_t field_name,
1459 			Lambda && lambda ) const
1460 				noexcept(noexcept(lambda(
1461 						std::declval<const string_view_t &>())))
1462 		{
1463 			static_assert(
1464 				std::is_same<
1465 					handling_result_t,
1466 					decltype(lambda(std::declval<const string_view_t &>()))
1467 				>::value,
1468 				"lambda should return restinio::http_header_fields_t::handling_result_t" );
1469 
1470 			for( const auto & f : m_fields )
1471 			{
1472 				if( impl::is_equal_caseless( f.name(), field_name ) )
1473 				{
1474 					const handling_result_t r = lambda( f.value() );
1475 					if( stop_enumeration() == r )
1476 						break;
1477 				}
1478 			}
1479 		}
1480 
1481 		const_iterator
begin() const1482 		begin() const noexcept
1483 		{
1484 			return m_fields.cbegin();
1485 		}
1486 
1487 		const_iterator
end() const1488 		end() const noexcept
1489 		{
1490 			return m_fields.cend();
1491 		}
1492 
fields_count() const1493 		auto fields_count() const noexcept
1494 		{
1495 			return m_fields.size();
1496 		}
1497 
1498 	private:
1499 		//! Appends last added field.
1500 		/*!
1501 			This is function is used by http-parser when
1502 			field value is created by 2 separate
1503 			invocation of on-header-field-value callback
1504 
1505 			Function doesn't check if at least one field exists,
1506 			so it is not in the public interface.
1507 		*/
1508 		void
append_last_field(string_view_t field_value)1509 		append_last_field( string_view_t field_value )
1510 		{
1511 			m_fields.back().append_value( field_value );
1512 		}
1513 
1514 		fields_container_t::iterator
find(string_view_t field_name)1515 		find( string_view_t field_name ) noexcept
1516 		{
1517 			return std::find_if(
1518 				m_fields.begin(),
1519 				m_fields.end(),
1520 				[&]( const auto & f ){
1521 					return impl::is_equal_caseless( f.name(), field_name );
1522 				} );
1523 		}
1524 
1525 		fields_container_t::const_iterator
cfind(string_view_t field_name) const1526 		cfind( string_view_t field_name ) const noexcept
1527 		{
1528 			return std::find_if(
1529 				m_fields.cbegin(),
1530 				m_fields.cend(),
1531 				[&]( const auto & f ){
1532 					return impl::is_equal_caseless( f.name(), field_name );
1533 				} );
1534 		}
1535 
1536 		fields_container_t::iterator
find(http_field_t field_id)1537 		find( http_field_t field_id ) noexcept
1538 		{
1539 			return std::find_if(
1540 				m_fields.begin(),
1541 				m_fields.end(),
1542 				[&]( const auto & f ){
1543 					return f.field_id() == field_id;
1544 				} );
1545 		}
1546 
1547 		fields_container_t::const_iterator
cfind(http_field_t field_id) const1548 		cfind( http_field_t field_id ) const noexcept
1549 		{
1550 			return std::find_if(
1551 				m_fields.cbegin(),
1552 				m_fields.cend(),
1553 				[&]( const auto & f ){
1554 					return f.field_id() == field_id;
1555 				} );
1556 		}
1557 
1558 		fields_container_t m_fields;
1559 };
1560 
1561 //
1562 // http_connection_header_t
1563 //
1564 
1565 //! Values for conection header field.
1566 enum class http_connection_header_t : std::uint8_t
1567 {
1568 	keep_alive,
1569 	close,
1570 	upgrade
1571 };
1572 
1573 //
1574 // http_header_common_t
1575 //
1576 
1577 //! Req/Resp headers common data.
1578 struct http_header_common_t
1579 	:	public http_header_fields_t
1580 {
1581 	public:
1582 		//! Http version.
1583 		//! \{
1584 		std::uint16_t
http_majorrestinio::http_header_common_t1585 		http_major() const noexcept
1586 		{ return m_http_major; }
1587 
1588 		void
http_majorrestinio::http_header_common_t1589 		http_major( std::uint16_t v ) noexcept
1590 		{ m_http_major = v; }
1591 
1592 		std::uint16_t
http_minorrestinio::http_header_common_t1593 		http_minor() const noexcept
1594 		{ return m_http_minor; }
1595 
1596 		void
http_minorrestinio::http_header_common_t1597 		http_minor( std::uint16_t v ) noexcept
1598 		{ m_http_minor = v; }
1599 		//! \}
1600 
1601 		//! Length of body of an http-message.
1602 		std::uint64_t
content_lengthrestinio::http_header_common_t1603 		content_length() const noexcept
1604 		{ return m_content_length; }
1605 
1606 		void
content_lengthrestinio::http_header_common_t1607 		content_length( std::uint64_t l ) noexcept
1608 		{ m_content_length = l; }
1609 
1610 		bool
should_keep_aliverestinio::http_header_common_t1611 		should_keep_alive() const noexcept
1612 		{
1613 			return http_connection_header_t::keep_alive == m_http_connection_header_field_value;
1614 		}
1615 
1616 		void
should_keep_aliverestinio::http_header_common_t1617 		should_keep_alive( bool keep_alive ) noexcept
1618 		{
1619 			connection( keep_alive?
1620 				http_connection_header_t::keep_alive :
1621 				http_connection_header_t::close );
1622 		}
1623 
1624 		//! Get the value of 'connection' header field.
1625 		http_connection_header_t
connectionrestinio::http_header_common_t1626 		connection() const
1627 		{
1628 			return m_http_connection_header_field_value;
1629 		}
1630 
1631 		//! Set the value of 'connection' header field.
1632 		void
connectionrestinio::http_header_common_t1633 		connection( http_connection_header_t ch ) noexcept
1634 		{
1635 			m_http_connection_header_field_value = ch;
1636 		}
1637 
1638 	private:
1639 		//! Http version.
1640 		//! \{
1641 		std::uint16_t m_http_major{1};
1642 		std::uint16_t m_http_minor{1};
1643 		//! \}
1644 
1645 		//! Length of body of an http-message.
1646 		std::uint64_t m_content_length{ 0 };
1647 
1648 		http_connection_header_t m_http_connection_header_field_value{ http_connection_header_t::close };
1649 };
1650 
1651 //! HTTP methods mapping with nodejs http methods
1652 #define RESTINIO_HTTP_METHOD_MAP(RESTINIO_GEN)         \
1653 	RESTINIO_GEN( http_method_delete,       HTTP_DELETE,       DELETE )       \
1654 	RESTINIO_GEN( http_method_get,          HTTP_GET,          GET )          \
1655 	RESTINIO_GEN( http_method_head,         HTTP_HEAD,         HEAD )         \
1656 	RESTINIO_GEN( http_method_post,         HTTP_POST,         POST )         \
1657 	RESTINIO_GEN( http_method_put,          HTTP_PUT,          PUT )          \
1658   /* pathological */                \
1659 	RESTINIO_GEN( http_method_connect,      HTTP_CONNECT,      CONNECT )      \
1660 	RESTINIO_GEN( http_method_options,      HTTP_OPTIONS,      OPTIONS )      \
1661 	RESTINIO_GEN( http_method_trace,        HTTP_TRACE,        TRACE )        \
1662   /* WebDAV */                      \
1663 	RESTINIO_GEN( http_method_copy,         HTTP_COPY,         COPY )         \
1664 	RESTINIO_GEN( http_method_lock,         HTTP_LOCK,         LOCK )         \
1665 	RESTINIO_GEN( http_method_mkcol,        HTTP_MKCOL,        MKCOL )        \
1666 	RESTINIO_GEN( http_method_move,         HTTP_MOVE,         MOVE )         \
1667 	RESTINIO_GEN( http_method_propfind,     HTTP_PROPFIND,     PROPFIND )     \
1668 	RESTINIO_GEN( http_method_proppatch,    HTTP_PROPPATCH,    PROPPATCH )    \
1669 	RESTINIO_GEN( http_method_search,       HTTP_SEARCH,       SEARCH )       \
1670 	RESTINIO_GEN( http_method_unlock,       HTTP_UNLOCK,       UNLOCK )       \
1671 	RESTINIO_GEN( http_method_bind,         HTTP_BIND,         BIND )         \
1672 	RESTINIO_GEN( http_method_rebind,       HTTP_REBIND,       REBIND )       \
1673 	RESTINIO_GEN( http_method_unbind,       HTTP_UNBIND,       UNBIND )       \
1674 	RESTINIO_GEN( http_method_acl,          HTTP_ACL,          ACL )          \
1675   /* subversion */                  \
1676 	RESTINIO_GEN( http_method_report,       HTTP_REPORT,       REPORT )       \
1677 	RESTINIO_GEN( http_method_mkactivity,   HTTP_MKACTIVITY,   MKACTIVITY )   \
1678 	RESTINIO_GEN( http_method_checkout,     HTTP_CHECKOUT,     CHECKOUT )     \
1679 	RESTINIO_GEN( http_method_merge,        HTTP_MERGE,        MERGE )        \
1680   /* upnp */                        \
1681 	RESTINIO_GEN( http_method_msearch,      HTTP_MSEARCH,      M-SEARCH)      \
1682 	RESTINIO_GEN( http_method_notify,       HTTP_NOTIFY,       NOTIFY )       \
1683 	RESTINIO_GEN( http_method_subscribe,    HTTP_SUBSCRIBE,    SUBSCRIBE )    \
1684 	RESTINIO_GEN( http_method_unsubscribe,  HTTP_UNSUBSCRIBE,  UNSUBSCRIBE )  \
1685   /* RFC-5789 */                    \
1686 	RESTINIO_GEN( http_method_patch,        HTTP_PATCH,        PATCH )        \
1687 	RESTINIO_GEN( http_method_purge,        HTTP_PURGE,        PURGE )        \
1688   /* CalDAV */                      \
1689 	RESTINIO_GEN( http_method_mkcalendar,   HTTP_MKCALENDAR,   MKCALENDAR )   \
1690   /* RFC-2068, section 19.6.1.2 */  \
1691 	RESTINIO_GEN( http_method_link,         HTTP_LINK,         LINK )         \
1692 	RESTINIO_GEN( http_method_unlink,       HTTP_UNLINK,       UNLINK )
1693 
1694 //
1695 // http_method_id_t
1696 //
1697 /*!
1698  * @brief A type for representation of HTTP method ID.
1699  *
1700  * RESTinio uses http_parser for working with HTTP-protocol.
1701  * HTTP-methods in http_parser are identified by `int`s like
1702  * HTTP_GET, HTTP_POST and so on.
1703  *
1704  * Usage of plain `int` is error prone. So since v.0.5.0 RESTinio contain
1705  * type http_method_id_t as type for ID of HTTP method.
1706  *
1707  * An instance of http_method_id_t contains two values:
1708  * * integer identifier from http_parser (like HTTP_GET, HTTP_POST and so on);
1709  * * a string representation of HTTP method ID (like "GET", "POST", "DELETE"
1710  * and so on).
1711  *
1712  * There is an important requirement for user-defined HTTP method IDs:
1713  * a pointer to string representation of HTTP method ID must outlive
1714  * the instance of http_method_id_t. It means that is safe to use string
1715  * literals or static strings, for example:
1716  * @code
1717  * constexpr const restinio::http_method_id_t my_http_method(255, "MY-METHOD");
1718  * @endcode
1719  *
1720  * @note
1721  * Instances of http_method_id_t can't be used in switch() operator.
1722  * For example, you can't write that way:
1723  * @code
1724  * const int method_id = ...;
1725  * switch(method_id) {
1726  * 	case restinio::http_method_get(): ...; break;
1727  * 	case restinio::http_method_post(): ...; break;
1728  * 	case restinio::http_method_delete(): ...; break;
1729  * }
1730  * @endcode
1731  * In that case raw_id() method can be used:
1732  * @code
1733  * const int method_id = ...;
1734  * switch(method_id) {
1735  * 	case restinio::http_method_get().raw_id(): ...; break;
1736  * 	case restinio::http_method_post().raw_id(): ...; break;
1737  * 	case restinio::http_method_delete().raw_id(): ...; break;
1738  * }
1739  * @endcode
1740  *
1741  * @since v.0.5.0
1742  */
1743 class http_method_id_t
1744 {
1745 	int m_value;
1746 	const char * m_name;
1747 
1748 public:
1749 	static constexpr const int unknown_method = -1;
1750 
http_method_id_t()1751 	constexpr http_method_id_t() noexcept
1752 		:	m_value{ unknown_method }
1753 		,	m_name{ "<undefined>" }
1754 		{}
http_method_id_t(int value,const char * name)1755 	constexpr http_method_id_t(
1756 		int value,
1757 		const char * name ) noexcept
1758 		:	m_value{ value }
1759 		,	m_name{ name }
1760 		{}
1761 
1762 	constexpr http_method_id_t( const http_method_id_t & ) noexcept = default;
1763 	constexpr http_method_id_t &
1764 	operator=( const http_method_id_t & ) noexcept = default;
1765 
1766 	constexpr http_method_id_t( http_method_id_t && ) noexcept = default;
1767 	constexpr http_method_id_t &
1768 	operator=( http_method_id_t && ) noexcept = default;
1769 
1770 	constexpr auto
raw_id() const1771 	raw_id() const noexcept { return m_value; }
1772 
1773 	constexpr const char *
c_str() const1774 	c_str() const noexcept { return m_name; }
1775 
1776 	friend constexpr bool
operator ==(const http_method_id_t & a,const http_method_id_t & b)1777 	operator==( const http_method_id_t & a, const http_method_id_t & b ) noexcept {
1778 		return a.raw_id() == b.raw_id();
1779 	}
1780 
1781 	friend constexpr bool
operator !=(const http_method_id_t & a,const http_method_id_t & b)1782 	operator!=( const http_method_id_t & a, const http_method_id_t & b ) noexcept {
1783 		return a.raw_id() != b.raw_id();
1784 	}
1785 
1786 	friend constexpr bool
operator <(const http_method_id_t & a,const http_method_id_t & b)1787 	operator<( const http_method_id_t & a, const http_method_id_t & b ) noexcept {
1788 		return a.raw_id() < b.raw_id();
1789 	}
1790 };
1791 
1792 inline std::ostream &
operator <<(std::ostream & to,const http_method_id_t & m)1793 operator<<( std::ostream & to, const http_method_id_t & m )
1794 {
1795 	return to << m.c_str();
1796 }
1797 
1798 // Generate helper funcs.
1799 #define RESTINIO_HTTP_METHOD_FUNC_GEN( func_name, nodejs_code, method_name ) \
1800 	inline constexpr http_method_id_t func_name() { \
1801 		return { nodejs_code, #method_name }; \
1802 	}
1803 
RESTINIO_HTTP_METHOD_MAP(RESTINIO_HTTP_METHOD_FUNC_GEN)1804 	RESTINIO_HTTP_METHOD_MAP( RESTINIO_HTTP_METHOD_FUNC_GEN )
1805 #undef RESTINIO_HTTP_METHOD_FUNC_GEN
1806 
1807 inline constexpr http_method_id_t
1808 http_method_unknown()
1809 {
1810 	return http_method_id_t{};
1811 }
1812 
1813 //
1814 // default_http_methods_t
1815 //
1816 /*!
1817  * @brief The default implementation for http_method_mapper.
1818  *
1819  * Since v.0.5.0 RESTinio allows to use modified versions of http_parser
1820  * libraries. Such modified versions can handle non-standard HTTP methods.
1821  * In that case a user should define its own http_method_mapper-type.
1822  * That http_method_mapper must contain static method from_nodejs for
1823  * mapping the http_parser's ID of HTTP method to an instance of
1824  * http_method_id_t.
1825  *
1826  * Class default_http_methods_t is the default implementation of
1827  * http_method_mapper-type for vanila version of http_parser.
1828  *
1829  * @since v.0.5.0
1830  */
1831 class default_http_methods_t
1832 {
1833 public :
1834 	inline static constexpr http_method_id_t
from_nodejs(int value)1835 	from_nodejs( int value ) noexcept
1836 	{
1837 		http_method_id_t result;
1838 		switch( value )
1839 		{
1840 #define RESTINIO_HTTP_METHOD_FUNC_GEN( func_name, nodejs_code, method_name ) \
1841 			case nodejs_code : result = func_name(); break;
1842 
1843 	RESTINIO_HTTP_METHOD_MAP( RESTINIO_HTTP_METHOD_FUNC_GEN )
1844 #undef RESTINIO_HTTP_METHOD_FUNC_GEN
1845 			default : ; // Nothing to do.
1846 		}
1847 
1848 		return result;
1849 	}
1850 };
1851 
1852 //
1853 // http_request_header
1854 //
1855 
1856 //! Req header.
1857 struct http_request_header_t final
1858 	:	public http_header_common_t
1859 {
1860 		static std::size_t
memchr_helperrestinio::http_request_header_t1861 		memchr_helper( int chr , const char * from, std::size_t size )
1862 		{
1863 			const char * result = static_cast< const char * >(
1864 					std::memchr( from, chr, size ) );
1865 
1866 			return result ? static_cast< std::size_t >( result - from ) : size;
1867 		}
1868 
1869 	public:
1870 		http_request_header_t() = default;
1871 
http_request_header_trestinio::http_request_header_t1872 		http_request_header_t(
1873 			http_method_id_t method,
1874 			std::string request_target_ )
1875 			:	m_method{ method }
1876 		{
1877 			request_target( std::move( request_target_ ) );
1878 		}
1879 
1880 		http_method_id_t
methodrestinio::http_request_header_t1881 		method() const noexcept
1882 		{ return m_method; }
1883 
1884 		void
methodrestinio::http_request_header_t1885 		method( http_method_id_t m ) noexcept
1886 		{ m_method = m; }
1887 
1888 		const std::string &
request_targetrestinio::http_request_header_t1889 		request_target() const noexcept
1890 		{ return m_request_target; }
1891 
1892 		void
request_targetrestinio::http_request_header_t1893 		request_target( std::string t )
1894 		{
1895 			m_request_target.assign( std::move( t ) );
1896 
1897 			m_fragment_separator_pos =
1898 				memchr_helper( '#', m_request_target.data(), m_request_target.size() );
1899 
1900 			m_query_separator_pos =
1901 				memchr_helper( '?', m_request_target.data(), m_fragment_separator_pos );
1902 		}
1903 
1904 		//! Request URL-structure.
1905 		//! \{
1906 
1907 		//! Get the path part of the request URL.
1908 		/*!
1909 			If request target is `/weather/temperature?from=2012-01-01&to=2012-01-10`,
1910 			then function returns string view on '/weather/temperature' part.
1911 		*/
1912 		string_view_t
pathrestinio::http_request_header_t1913 		path() const noexcept
1914 		{
1915 			return string_view_t{ m_request_target.data(), m_query_separator_pos };
1916 		}
1917 
1918 		//! Get the query part of the request URL.
1919 		/*!
1920 			If request target is `/weather/temperature?from=2012-01-01&to=2012-01-10`,
1921 			then function returns string view on 'from=2012-01-01&to=2012-01-10' part.
1922 		*/
1923 		string_view_t
queryrestinio::http_request_header_t1924 		query() const noexcept
1925 		{
1926 			return
1927 				m_fragment_separator_pos == m_query_separator_pos ?
1928 				string_view_t{ nullptr, 0 } :
1929 				string_view_t{
1930 					m_request_target.data() + m_query_separator_pos + 1,
1931 					m_fragment_separator_pos - m_query_separator_pos - 1 };
1932 		}
1933 
1934 
1935 		//! Get the fragment part of the request URL.
1936 		/*!
1937 			If request target is `/sobjectizerteam/json_dto-0.2#markdown-header-what-is-json_dto`,
1938 			then function returns string view on 'markdown-header-what-is-json_dto' part.
1939 		*/
1940 		string_view_t
fragmentrestinio::http_request_header_t1941 		fragment() const
1942 		{
1943 			return
1944 				m_request_target.size() == m_fragment_separator_pos ?
1945 				string_view_t{ nullptr, 0 } :
1946 				string_view_t{
1947 					m_request_target.data() + m_fragment_separator_pos + 1,
1948 					m_request_target.size() - m_fragment_separator_pos - 1 };
1949 		}
1950 		//! \}
1951 
1952 		//! Helpfull function for using in parser callback.
1953 		void
append_request_targetrestinio::http_request_header_t1954 		append_request_target( const char * at, size_t length )
1955 		{
1956 			if( m_request_target.size() == m_fragment_separator_pos )
1957 			{
1958 				// If fragment separator hadn't  already appeared,
1959 				// search for it in a new block.
1960 
1961 				const auto fragment_separator_pos_inc =
1962 					memchr_helper( '#', at, length );
1963 
1964 				m_fragment_separator_pos += fragment_separator_pos_inc;
1965 
1966 				if( m_request_target.size() == m_query_separator_pos )
1967 				{
1968 					// If request separator hadn't already appeared,
1969 					// search for it in a new block.
1970 					m_query_separator_pos +=
1971 						memchr_helper( '?', at, fragment_separator_pos_inc );
1972 				}
1973 			}
1974 			// Else fragment separator appeared
1975 			// (req separator is either already defined or does not exist)
1976 
1977 			m_request_target.append( at, length );
1978 		}
1979 
1980 	private:
1981 		http_method_id_t m_method{ http_method_get() };
1982 		std::string m_request_target;
1983 		std::size_t m_query_separator_pos{ 0 };
1984 		std::size_t m_fragment_separator_pos{ 0 };
1985 };
1986 
1987 //
1988 // http_status_code_t
1989 //
1990 
1991 //! A handy wrapper for HTTP response status code.
1992 class http_status_code_t
1993 {
1994 	public:
http_status_code_t()1995 		constexpr http_status_code_t() noexcept
1996 		{}
1997 
http_status_code_t(std::uint16_t status_code)1998 		constexpr explicit http_status_code_t( std::uint16_t status_code ) noexcept
1999 			:	m_status_code{ status_code }
2000 		{}
2001 
2002 		constexpr auto
raw_code() const2003 		raw_code() const noexcept
2004 		{
2005 			return m_status_code;
2006 		}
2007 
2008 		constexpr bool
operator ==(const http_status_code_t & sc) const2009 		operator == ( const http_status_code_t & sc ) const noexcept
2010 		{
2011 			return raw_code() == sc.raw_code();
2012 		}
2013 
2014 		constexpr bool
operator !=(const http_status_code_t & sc) const2015 		operator != ( const http_status_code_t & sc ) const noexcept
2016 		{
2017 			return sc.raw_code() != sc.raw_code();
2018 		}
2019 
2020 		constexpr bool
operator <(const http_status_code_t & sc) const2021 		operator < ( const http_status_code_t & sc ) const noexcept
2022 		{
2023 			return sc.raw_code() < sc.raw_code();
2024 		}
2025 
2026 	private:
2027 		//! Status code value.
2028 		std::uint16_t m_status_code{ 0 };
2029 };
2030 
2031 namespace status_code
2032 {
2033 
2034 /** @name RFC 2616 status code list.
2035  * @brief Codes defined by RFC 2616: https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1.
2036 */
2037 ///@{
2038 
2039 // Add '_', because 'continue is reserved word.'
2040 constexpr http_status_code_t continue_{ 100 };
2041 
2042 constexpr http_status_code_t switching_protocols{ 101 };
2043 constexpr http_status_code_t ok{ 200 };
2044 constexpr http_status_code_t created{ 201 };
2045 constexpr http_status_code_t accepted{ 202 };
2046 constexpr http_status_code_t non_authoritative_information{ 203 };
2047 constexpr http_status_code_t no_content{ 204 };
2048 constexpr http_status_code_t reset_content{ 205 };
2049 constexpr http_status_code_t partial_content{ 206 };
2050 constexpr http_status_code_t multiple_choices{ 300 };
2051 constexpr http_status_code_t moved_permanently{ 301 };
2052 constexpr http_status_code_t found{ 302 };
2053 constexpr http_status_code_t see_other{ 303 };
2054 constexpr http_status_code_t not_modified{ 304 };
2055 constexpr http_status_code_t use_proxy{ 305 };
2056 constexpr http_status_code_t temporary_redirect{ 307 };
2057 constexpr http_status_code_t bad_request{ 400 };
2058 constexpr http_status_code_t unauthorized{ 401 };
2059 constexpr http_status_code_t payment_required{ 402 };
2060 constexpr http_status_code_t forbidden{ 403 };
2061 constexpr http_status_code_t not_found{ 404 };
2062 constexpr http_status_code_t method_not_allowed{ 405 };
2063 constexpr http_status_code_t not_acceptable{ 406 };
2064 constexpr http_status_code_t proxy_authentication_required{ 407 };
2065 constexpr http_status_code_t request_time_out{ 408 };
2066 constexpr http_status_code_t conflict{ 409 };
2067 constexpr http_status_code_t gone{ 410 };
2068 constexpr http_status_code_t length_required{ 411 };
2069 constexpr http_status_code_t precondition_failed{ 412 };
2070 
2071 //413 Payload Too Large (RFC 7231)
2072 // The request is larger than the server is willing or able to process.
2073 // Previously called "Request Entity Too Large".[44]
2074 constexpr http_status_code_t payload_too_large{ 413 };
2075 
2076 // 414 URI Too Long (RFC 7231)
2077 // The URI provided was too long for the server to process.
2078 // Often the result of too much data being encoded as a query-string of a GET request,
2079 // in which case it should be converted to a POST request.
2080 // Called "Request-URI Too Long" previously.[46]
2081 constexpr http_status_code_t uri_too_long{ 414 };
2082 
2083 constexpr http_status_code_t unsupported_media_type{ 415 };
2084 constexpr http_status_code_t requested_range_not_satisfiable{ 416 };
2085 constexpr http_status_code_t expectation_failed{ 417 };
2086 constexpr http_status_code_t internal_server_error{ 500 };
2087 constexpr http_status_code_t not_implemented{ 501 };
2088 constexpr http_status_code_t bad_gateway{ 502 };
2089 constexpr http_status_code_t service_unavailable{ 503 };
2090 constexpr http_status_code_t gateway_time_out{ 504 };
2091 constexpr http_status_code_t http_version_not_supported{ 505 };
2092 ///@}
2093 
2094 /** @name Additional status codes.
2095  * @brief Codes not covered with RFC 2616.
2096 */
2097 ///@{
2098 	// RFC 7538
2099 constexpr http_status_code_t permanent_redirect{ 308 };
2100 
2101 	// RFC 2518
2102 constexpr http_status_code_t processing{ 102 };
2103 constexpr http_status_code_t multi_status{ 207 };
2104 constexpr http_status_code_t unprocessable_entity{ 422 };
2105 constexpr http_status_code_t locked{ 423 };
2106 constexpr http_status_code_t failed_dependency{ 424 };
2107 constexpr http_status_code_t insufficient_storage{ 507 };
2108 
2109 	// RFC 6585
2110 constexpr http_status_code_t precondition_required{ 428 };
2111 constexpr http_status_code_t too_many_requests{ 429 };
2112 constexpr http_status_code_t request_header_fields_too_large{ 431 };
2113 constexpr http_status_code_t network_authentication_required{ 511 };
2114 ///@}
2115 
2116 } /* namespace status_code */
2117 
2118 //
2119 // http_status_line_t
2120 //
2121 
2122 //! HTTP response header status line.
2123 class http_status_line_t
2124 {
2125 	public:
http_status_line_t()2126 		http_status_line_t()
2127 		{}
2128 
http_status_line_t(http_status_code_t sc,std::string reason_phrase)2129 		http_status_line_t(
2130 			http_status_code_t sc,
2131 			std::string reason_phrase )
2132 			:	m_status_code{ sc }
2133 			,	m_reason_phrase{ std::move( reason_phrase ) }
2134 		{}
2135 
2136 		http_status_code_t
status_code() const2137 		status_code() const noexcept
2138 		{ return m_status_code; }
2139 
2140 		void
status_code(http_status_code_t c)2141 		status_code( http_status_code_t c ) noexcept
2142 		{ m_status_code = c; }
2143 
2144 		const std::string &
reason_phrase() const2145 		reason_phrase() const noexcept
2146 		{ return m_reason_phrase; }
2147 
2148 		void
reason_phrase(std::string r)2149 		reason_phrase( std::string r )
2150 		{ m_reason_phrase.assign( std::move( r ) ); }
2151 
2152 	private:
2153 		http_status_code_t m_status_code{ status_code::ok };
2154 		std::string m_reason_phrase;
2155 };
2156 
2157 inline std::ostream &
operator <<(std::ostream & o,const http_status_line_t & status_line)2158 operator << ( std::ostream & o, const http_status_line_t & status_line )
2159 {
2160 	return o << "{" << status_line.status_code().raw_code() << ", "
2161 			<< status_line.reason_phrase() << "}";
2162 }
2163 
2164 /** @name RFC 2616 statuses.
2165  * @brief Codes defined by RFC 2616: https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1.1.
2166 */
2167 ///@{
2168 
status_continue()2169 inline http_status_line_t status_continue()
2170 { return http_status_line_t{ status_code::continue_, "Continue" }; }
2171 
status_switching_protocols()2172 inline http_status_line_t status_switching_protocols()
2173 { return http_status_line_t{ status_code::switching_protocols, "Switching Protocols" }; }
2174 
status_ok()2175 inline http_status_line_t status_ok()
2176 { return http_status_line_t{ status_code::ok, "OK" }; }
2177 
status_created()2178 inline http_status_line_t status_created()
2179 { return http_status_line_t{ status_code::created, "Created" }; }
2180 
status_accepted()2181 inline http_status_line_t status_accepted()
2182 { return http_status_line_t{ status_code::accepted, "Accepted" }; }
2183 
status_non_authoritative_information()2184 inline http_status_line_t status_non_authoritative_information()
2185 { return http_status_line_t{ status_code::non_authoritative_information, "Non-Authoritative Information" }; }
2186 
status_no_content()2187 inline http_status_line_t status_no_content()
2188 { return http_status_line_t{ status_code::no_content, "No Content" }; }
2189 
status_reset_content()2190 inline http_status_line_t status_reset_content()
2191 { return http_status_line_t{ status_code::reset_content, "Reset Content" }; }
2192 
status_partial_content()2193 inline http_status_line_t status_partial_content()
2194 { return http_status_line_t{ status_code::partial_content, "Partial Content" }; }
2195 
status_multiple_choices()2196 inline http_status_line_t status_multiple_choices()
2197 { return http_status_line_t{ status_code::multiple_choices, "Multiple Choices" }; }
2198 
status_moved_permanently()2199 inline http_status_line_t status_moved_permanently()
2200 { return http_status_line_t{ status_code::moved_permanently, "Moved Permanently" }; }
2201 
status_found()2202 inline http_status_line_t status_found()
2203 { return http_status_line_t{ status_code::found, "Found" }; }
2204 
status_see_other()2205 inline http_status_line_t status_see_other()
2206 { return http_status_line_t{ status_code::see_other, "See Other" }; }
2207 
status_not_modified()2208 inline http_status_line_t status_not_modified()
2209 { return http_status_line_t{ status_code::not_modified, "Not Modified" }; }
2210 
status_use_proxy()2211 inline http_status_line_t status_use_proxy()
2212 { return http_status_line_t{ status_code::use_proxy, "Use Proxy" }; }
2213 
status_temporary_redirect()2214 inline http_status_line_t status_temporary_redirect()
2215 { return http_status_line_t{ status_code::temporary_redirect, "Temporary Redirect" }; }
2216 
status_bad_request()2217 inline http_status_line_t status_bad_request()
2218 { return http_status_line_t{ status_code::bad_request, "Bad Request" }; }
2219 
status_unauthorized()2220 inline http_status_line_t status_unauthorized()
2221 { return http_status_line_t{ status_code::unauthorized, "Unauthorized" }; }
2222 
status_payment_required()2223 inline http_status_line_t status_payment_required()
2224 { return http_status_line_t{ status_code::payment_required, "Payment Required" }; }
2225 
status_forbidden()2226 inline http_status_line_t status_forbidden()
2227 { return http_status_line_t{ status_code::forbidden, "Forbidden" }; }
2228 
status_not_found()2229 inline http_status_line_t status_not_found()
2230 { return http_status_line_t{ status_code::not_found, "Not Found" }; }
2231 
status_method_not_allowed()2232 inline http_status_line_t status_method_not_allowed()
2233 { return http_status_line_t{ status_code::method_not_allowed, "Method Not Allowed" }; }
2234 
status_not_acceptable()2235 inline http_status_line_t status_not_acceptable()
2236 { return http_status_line_t{ status_code::not_acceptable, "Not Acceptable" }; }
2237 
status_proxy_authentication_required()2238 inline http_status_line_t status_proxy_authentication_required()
2239 { return http_status_line_t{status_code::proxy_authentication_required, "Proxy Authentication Required" }; }
2240 
status_request_time_out()2241 inline http_status_line_t status_request_time_out()
2242 { return http_status_line_t{ status_code::request_time_out, "Request Timeout" }; }
2243 
status_conflict()2244 inline http_status_line_t status_conflict()
2245 { return http_status_line_t{ status_code::conflict, "Conflict" }; }
2246 
status_gone()2247 inline http_status_line_t status_gone()
2248 { return http_status_line_t{ status_code::gone, "Gone" }; }
2249 
status_length_required()2250 inline http_status_line_t status_length_required()
2251 { return http_status_line_t{ status_code::length_required, "Length Required" }; }
2252 
status_precondition_failed()2253 inline http_status_line_t status_precondition_failed()
2254 { return http_status_line_t{ status_code::precondition_failed, "Precondition Failed" }; }
2255 
status_payload_too_large()2256 inline http_status_line_t status_payload_too_large()
2257 { return http_status_line_t{ status_code::payload_too_large, "Payload Too Large" }; }
2258 
status_uri_too_long()2259 inline http_status_line_t status_uri_too_long()
2260 { return http_status_line_t{ status_code::uri_too_long, "URI Too Long" }; }
2261 
status_unsupported_media_type()2262 inline http_status_line_t status_unsupported_media_type()
2263 { return http_status_line_t{ status_code::unsupported_media_type, "Unsupported Media Type" }; }
2264 
status_requested_range_not_satisfiable()2265 inline http_status_line_t status_requested_range_not_satisfiable()
2266 { return http_status_line_t{ status_code::requested_range_not_satisfiable, "Requested Range Not Satisfiable" }; }
2267 
status_expectation_failed()2268 inline http_status_line_t status_expectation_failed()
2269 { return http_status_line_t{ status_code::expectation_failed, "Expectation Failed" }; }
2270 
status_internal_server_error()2271 inline http_status_line_t status_internal_server_error()
2272 { return http_status_line_t{ status_code::internal_server_error, "Internal Server Error" }; }
2273 
status_not_implemented()2274 inline http_status_line_t status_not_implemented()
2275 { return http_status_line_t{ status_code::not_implemented, "Not Implemented" }; }
2276 
status_bad_gateway()2277 inline http_status_line_t status_bad_gateway()
2278 { return http_status_line_t{ status_code::bad_gateway, "Bad Gateway" }; }
2279 
status_service_unavailable()2280 inline http_status_line_t status_service_unavailable()
2281 { return http_status_line_t{ status_code::service_unavailable, "Service Unavailable" }; }
2282 
status_gateway_time_out()2283 inline http_status_line_t status_gateway_time_out()
2284 { return http_status_line_t{ status_code::gateway_time_out, "Gateway Timeout" }; }
2285 
status_http_version_not_supported()2286 inline http_status_line_t status_http_version_not_supported()
2287 { return http_status_line_t{ status_code::http_version_not_supported, "HTTP Version not supported" }; }
2288 ///@}
2289 
2290 /** @name Additional statuses.
2291  * @brief Not covered with RFC 2616.
2292 */
2293 ///@{
2294 	// RFC 7538
status_permanent_redirect()2295 inline http_status_line_t status_permanent_redirect()
2296 { return http_status_line_t{ status_code::permanent_redirect, "Permanent Redirect" }; }
2297 
2298 	// RFC 2518
status_processing()2299 inline http_status_line_t status_processing()
2300 { return http_status_line_t{ status_code::processing, "Processing" }; }
2301 
status_multi_status()2302 inline http_status_line_t status_multi_status()
2303 { return http_status_line_t{ status_code::multi_status, "Multi-Status" }; }
2304 
status_unprocessable_entity()2305 inline http_status_line_t status_unprocessable_entity()
2306 { return http_status_line_t{ status_code::unprocessable_entity, "Unprocessable Entity" }; }
2307 
status_locked()2308 inline http_status_line_t status_locked()
2309 { return http_status_line_t{ status_code::locked, "Locked" }; }
2310 
status_failed_dependency()2311 inline http_status_line_t status_failed_dependency()
2312 { return http_status_line_t{ status_code::failed_dependency, "Failed Dependency" }; }
2313 
status_insufficient_storage()2314 inline http_status_line_t status_insufficient_storage()
2315 { return http_status_line_t{ status_code::insufficient_storage, "Insufficient Storage" }; }
2316 
2317 	// RFC 6585
status_precondition_required()2318 inline http_status_line_t status_precondition_required()
2319 { return http_status_line_t{ status_code::precondition_required, "Precondition Required" }; }
2320 
status_too_many_requests()2321 inline http_status_line_t status_too_many_requests()
2322 { return http_status_line_t{ status_code::too_many_requests, "Too Many Requests" }; }
2323 
status_request_header_fields_too_large()2324 inline http_status_line_t status_request_header_fields_too_large()
2325 { return http_status_line_t{ status_code::request_header_fields_too_large, "Request Header Fields Too Large" }; }
2326 
status_network_authentication_required()2327 inline http_status_line_t status_network_authentication_required()
2328 { return http_status_line_t{ status_code::network_authentication_required, "Network Authentication Required" }; }
2329 ///@}
2330 
2331 //
2332 // http_response_header_t
2333 //
2334 
2335 //! Resp header.
2336 struct http_response_header_t final
2337 	:	public http_header_common_t
2338 {
2339 	public:
http_response_header_trestinio::http_response_header_t2340 		http_response_header_t()
2341 		{}
2342 
http_response_header_trestinio::http_response_header_t2343 		http_response_header_t( http_status_line_t status_line )
2344 			:	m_status_line{ std::move( status_line ) }
2345 		{}
2346 
2347 		http_status_code_t
status_coderestinio::http_response_header_t2348 		status_code() const noexcept
2349 		{ return m_status_line.status_code(); }
2350 
2351 		void
status_coderestinio::http_response_header_t2352 		status_code( http_status_code_t c ) noexcept
2353 		{ m_status_line.status_code( c ); }
2354 
2355 		const std::string &
reason_phraserestinio::http_response_header_t2356 		reason_phrase() const noexcept
2357 		{ return m_status_line.reason_phrase(); }
2358 
2359 		void
reason_phraserestinio::http_response_header_t2360 		reason_phrase( std::string r )
2361 		{ m_status_line.reason_phrase( std::move( r ) ); }
2362 
2363 		const http_status_line_t &
status_linerestinio::http_response_header_t2364 		status_line() const noexcept
2365 		{
2366 			return m_status_line;
2367 		}
2368 
2369 		void
status_linerestinio::http_response_header_t2370 		status_line( http_status_line_t sl )
2371 		{
2372 			m_status_line = std::move( sl );
2373 		}
2374 
2375 	private:
2376 		http_status_line_t m_status_line;
2377 };
2378 
2379 } /* namespace restinio */
2380