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