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 <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,
236 #undef RESTINIO_HTTP_FIELD_GEN
237  // Unspecified field.
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
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:
268  break;
269 
270  case 3:
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 
545 }
546 
547 //
548 // field_to_string()
549 //
550 
551 //! Helper sunction to get method string name.
552 inline const char *
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 */
583 {
584  public:
587  {}
588 
590  std::string name,
591  std::string value )
592  : m_name{ std::move( name ) }
593  , m_value{ std::move( value ) }
595  {}
596 
598  string_view_t name,
599  string_view_t value )
600  : m_name{ name.data(), name.size() }
601  , m_value{ value.data(), value.size() }
603  {}
604 
606  http_field_t field_id,
607  std::string value )
609  , m_value{ std::move( value ) }
610  , m_field_id{ field_id }
611  {}
612 
614  http_field_t field_id,
615  string_view_t value )
617  , m_value{ std::move( value ) }
618  , m_field_id{ field_id }
619  {}
620 
621  const std::string & name() const noexcept { return m_name; }
622  const std::string & value() const noexcept { return m_value; }
623  http_field_t field_id() const noexcept { return m_field_id; }
624 
625  void
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
633  value( std::string v )
634  {
635  m_value = std::move( v );
636  }
637 
638  void
639  append_value( string_view_t v )
640  {
641  m_value.append( v.data(), v.size() );
642  }
643 
644  void
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:
655 };
656 
657 // Make neccessary forward declarations.
659 namespace impl
660 {
661 
662 void
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 */
703 {
704  friend void
706 
707  public:
709 
710  //! Type of const_iterator for enumeration of fields.
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.
725  //! The loop on field values should be stopped.
727  };
728 
729  constexpr static handling_result_t continue_enumeration() noexcept
731 
732  constexpr static handling_result_t stop_enumeration() noexcept
734 
736  {
738  }
739  http_header_fields_t(const http_header_fields_t &) = default;
741  virtual ~http_header_fields_t() {}
742 
743  http_header_fields_t & operator=(const http_header_fields_t &) = default;
745 
746  void
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
754  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
766  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
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
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
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
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
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
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
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
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 &
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  */
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 &
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>
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
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
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
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
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
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
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
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
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
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
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
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
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.
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.
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  */
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  */
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
1361  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
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<
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
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<
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 
1482  begin() const noexcept
1483  {
1484  return m_fields.cbegin();
1485  }
1486 
1488  end() const noexcept
1489  {
1490  return m_fields.cend();
1491  }
1492 
1493  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
1509  append_last_field( string_view_t field_value )
1510  {
1511  m_fields.back().append_value( field_value );
1512  }
1513 
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 
1526  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 
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 
1548  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 
1559 };
1560 
1561 //
1562 // http_connection_header_t
1563 //
1564 
1565 //! Values for conection header field.
1567 {
1568  keep_alive,
1569  close,
1570  upgrade
1571 };
1572 
1573 //
1574 // http_header_common_t
1575 //
1576 
1577 //! Req/Resp headers common data.
1579  : public http_header_fields_t
1580 {
1581  public:
1582  //! Http version.
1583  //! \{
1584  std::uint16_t
1585  http_major() const noexcept
1586  { return m_http_major; }
1587 
1588  void
1589  http_major( std::uint16_t v ) noexcept
1590  { m_http_major = v; }
1591 
1592  std::uint16_t
1593  http_minor() const noexcept
1594  { return m_http_minor; }
1595 
1596  void
1597  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
1603  content_length() const noexcept
1604  { return m_content_length; }
1605 
1606  void
1607  content_length( std::uint64_t l ) noexcept
1608  { m_content_length = l; }
1609 
1610  bool
1611  should_keep_alive() const noexcept
1612  {
1614  }
1615 
1616  void
1617  should_keep_alive( bool keep_alive ) noexcept
1618  {
1619  connection( keep_alive?
1622  }
1623 
1624  //! Get the value of 'connection' header field.
1626  connection() const
1627  {
1629  }
1630 
1631  //! Set the value of 'connection' header field.
1632  void
1634  {
1636  }
1637 
1638  private:
1639  //! Http version.
1640  //! \{
1643  //! \}
1644 
1645  //! Length of body of an http-message.
1647 
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  */
1744 {
1745  int m_value;
1746  const char * m_name;
1747 
1748 public:
1749  static constexpr const int unknown_method = -1;
1750 
1751  constexpr http_method_id_t() noexcept
1752  : m_value{ unknown_method }
1753  , m_name{ "<undefined>" }
1754  {}
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
1771  raw_id() const noexcept { return m_value; }
1772 
1773  constexpr const char *
1774  c_str() const noexcept { return m_name; }
1775 
1776  friend constexpr bool
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
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
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 &
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 
1805 #undef RESTINIO_HTTP_METHOD_FUNC_GEN
1806 
1807 inline constexpr http_method_id_t
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  */
1832 {
1833 public :
1834  inline static constexpr http_method_id_t
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
1861  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 
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 
1881  method() const noexcept
1882  { return m_method; }
1883 
1884  void
1885  method( http_method_id_t m ) noexcept
1886  { m_method = m; }
1887 
1888  const std::string &
1889  request_target() const noexcept
1890  { return m_request_target; }
1891 
1892  void
1893  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  */
1913  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  */
1924  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  */
1941  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
1954  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() };
1985 };
1986 
1987 //
1988 // http_status_code_t
1989 //
1990 
1991 //! A handy wrapper for HTTP response status code.
1993 {
1994  public:
1995  constexpr http_status_code_t() noexcept
1996  {}
1997 
1998  constexpr explicit http_status_code_t( std::uint16_t status_code ) noexcept
2000  {}
2001 
2002  constexpr auto
2003  raw_code() const noexcept
2004  {
2005  return m_status_code;
2006  }
2007 
2008  constexpr bool
2009  operator == ( const http_status_code_t & sc ) const noexcept
2010  {
2011  return raw_code() == sc.raw_code();
2012  }
2013 
2014  constexpr bool
2015  operator != ( const http_status_code_t & sc ) const noexcept
2016  {
2017  return sc.raw_code() != sc.raw_code();
2018  }
2019 
2020  constexpr bool
2021  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.
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.'
2041 
2043 constexpr http_status_code_t ok{ 200 };
2044 constexpr http_status_code_t created{ 201 };
2045 constexpr http_status_code_t accepted{ 202 };
2052 constexpr http_status_code_t found{ 302 };
2066 constexpr http_status_code_t conflict{ 409 };
2067 constexpr http_status_code_t gone{ 410 };
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]
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]
2082 
2092 ///@}
2093 
2094 /** @name Additional status codes.
2095  * @brief Codes not covered with RFC 2616.
2096 */
2097 ///@{
2098  // RFC 7538
2100 
2101  // RFC 2518
2105 constexpr http_status_code_t locked{ 423 };
2108 
2109  // RFC 6585
2114 ///@}
2115 
2116 } /* namespace status_code */
2117 
2118 //
2119 // http_status_line_t
2120 //
2121 
2122 //! HTTP response header status line.
2124 {
2125  public:
2127  {}
2128 
2130  http_status_code_t sc,
2131  std::string reason_phrase )
2132  : m_status_code{ sc }
2134  {}
2135 
2137  status_code() const noexcept
2138  { return m_status_code; }
2139 
2140  void
2142  { m_status_code = c; }
2143 
2144  const std::string &
2145  reason_phrase() const noexcept
2146  { return m_reason_phrase; }
2147 
2148  void
2149  reason_phrase( std::string r )
2150  { m_reason_phrase.assign( std::move( r ) ); }
2151 
2152  private:
2155 };
2156 
2157 inline std::ostream &
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 
2170 { return http_status_line_t{ status_code::continue_, "Continue" }; }
2171 
2173 { return http_status_line_t{ status_code::switching_protocols, "Switching Protocols" }; }
2174 
2176 { return http_status_line_t{ status_code::ok, "OK" }; }
2177 
2179 { return http_status_line_t{ status_code::created, "Created" }; }
2180 
2182 { return http_status_line_t{ status_code::accepted, "Accepted" }; }
2183 
2185 { return http_status_line_t{ status_code::non_authoritative_information, "Non-Authoritative Information" }; }
2186 
2188 { return http_status_line_t{ status_code::no_content, "No Content" }; }
2189 
2191 { return http_status_line_t{ status_code::reset_content, "Reset Content" }; }
2192 
2194 { return http_status_line_t{ status_code::partial_content, "Partial Content" }; }
2195 
2197 { return http_status_line_t{ status_code::multiple_choices, "Multiple Choices" }; }
2198 
2200 { return http_status_line_t{ status_code::moved_permanently, "Moved Permanently" }; }
2201 
2203 { return http_status_line_t{ status_code::found, "Found" }; }
2204 
2206 { return http_status_line_t{ status_code::see_other, "See Other" }; }
2207 
2209 { return http_status_line_t{ status_code::not_modified, "Not Modified" }; }
2210 
2212 { return http_status_line_t{ status_code::use_proxy, "Use Proxy" }; }
2213 
2215 { return http_status_line_t{ status_code::temporary_redirect, "Temporary Redirect" }; }
2216 
2218 { return http_status_line_t{ status_code::bad_request, "Bad Request" }; }
2219 
2221 { return http_status_line_t{ status_code::unauthorized, "Unauthorized" }; }
2222 
2224 { return http_status_line_t{ status_code::payment_required, "Payment Required" }; }
2225 
2227 { return http_status_line_t{ status_code::forbidden, "Forbidden" }; }
2228 
2230 { return http_status_line_t{ status_code::not_found, "Not Found" }; }
2231 
2233 { return http_status_line_t{ status_code::method_not_allowed, "Method Not Allowed" }; }
2234 
2236 { return http_status_line_t{ status_code::not_acceptable, "Not Acceptable" }; }
2237 
2239 { return http_status_line_t{status_code::proxy_authentication_required, "Proxy Authentication Required" }; }
2240 
2242 { return http_status_line_t{ status_code::request_time_out, "Request Timeout" }; }
2243 
2245 { return http_status_line_t{ status_code::conflict, "Conflict" }; }
2246 
2248 { return http_status_line_t{ status_code::gone, "Gone" }; }
2249 
2251 { return http_status_line_t{ status_code::length_required, "Length Required" }; }
2252 
2254 { return http_status_line_t{ status_code::precondition_failed, "Precondition Failed" }; }
2255 
2257 { return http_status_line_t{ status_code::payload_too_large, "Payload Too Large" }; }
2258 
2260 { return http_status_line_t{ status_code::uri_too_long, "URI Too Long" }; }
2261 
2263 { return http_status_line_t{ status_code::unsupported_media_type, "Unsupported Media Type" }; }
2264 
2266 { return http_status_line_t{ status_code::requested_range_not_satisfiable, "Requested Range Not Satisfiable" }; }
2267 
2269 { return http_status_line_t{ status_code::expectation_failed, "Expectation Failed" }; }
2270 
2272 { return http_status_line_t{ status_code::internal_server_error, "Internal Server Error" }; }
2273 
2275 { return http_status_line_t{ status_code::not_implemented, "Not Implemented" }; }
2276 
2278 { return http_status_line_t{ status_code::bad_gateway, "Bad Gateway" }; }
2279 
2281 { return http_status_line_t{ status_code::service_unavailable, "Service Unavailable" }; }
2282 
2284 { return http_status_line_t{ status_code::gateway_time_out, "Gateway Timeout" }; }
2285 
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
2296 { return http_status_line_t{ status_code::permanent_redirect, "Permanent Redirect" }; }
2297 
2298  // RFC 2518
2300 { return http_status_line_t{ status_code::processing, "Processing" }; }
2301 
2303 { return http_status_line_t{ status_code::multi_status, "Multi-Status" }; }
2304 
2306 { return http_status_line_t{ status_code::unprocessable_entity, "Unprocessable Entity" }; }
2307 
2309 { return http_status_line_t{ status_code::locked, "Locked" }; }
2310 
2312 { return http_status_line_t{ status_code::failed_dependency, "Failed Dependency" }; }
2313 
2315 { return http_status_line_t{ status_code::insufficient_storage, "Insufficient Storage" }; }
2316 
2317  // RFC 6585
2319 { return http_status_line_t{ status_code::precondition_required, "Precondition Required" }; }
2320 
2322 { return http_status_line_t{ status_code::too_many_requests, "Too Many Requests" }; }
2323 
2325 { return http_status_line_t{ status_code::request_header_fields_too_large, "Request Header Fields Too Large" }; }
2326 
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:
2341  {}
2342 
2345  {}
2346 
2348  status_code() const noexcept
2349  { return m_status_line.status_code(); }
2350 
2351  void
2353  { m_status_line.status_code( c ); }
2354 
2355  const std::string &
2356  reason_phrase() const noexcept
2357  { return m_status_line.reason_phrase(); }
2358 
2359  void
2360  reason_phrase( std::string r )
2361  { m_status_line.reason_phrase( std::move( r ) ); }
2362 
2363  const http_status_line_t &
2364  status_line() const noexcept
2365  {
2366  return m_status_line;
2367  }
2368 
2369  void
2371  {
2372  m_status_line = std::move( sl );
2373  }
2374 
2375  private:
2377 };
2378 
2379 } /* 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
void for_each_value_of(string_view_t field_name, Lambda &&lambda) const noexcept(noexcept(lambda(std::declval< const string_view_t &>())))
Enumeration of each value of a field.
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
handling_result_t
The result of handling yet another field value.
static constexpr handling_result_t stop_enumeration() noexcept
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.
void for_each_value_of(http_field_t field_id, Lambda &&lambda) const noexcept(noexcept(lambda(std::declval< const string_view_t &>())))
Enumeration of each value of a field.
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
void add_field(http_header_field_t http_header_field)
Add a field in the form of http_header_field object.
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.
void add_field(std::string field_name, std::string field_value)
Add a field in the form of name-value pair.
http_status_line_t status_not_modified()
A single header field.
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)
bool remove_field(http_field_t field_id) noexcept
Remove field by id.
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 add_field(http_field_t field_id, std::string field_value)
Add a field in the form of id-value pair.
void append_last_field(string_view_t field_value)
Appends last added field.
const_iterator begin() const noexcept
Next value of field should be found and passed to the next invocation of handler. ...
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)
std::size_t remove_all_of(string_view_t field_name) noexcept
Remove all occurences of a field with specified 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()
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.
static constexpr handling_result_t continue_enumeration() noexcept
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.
RESTINIO_NODISCARD char to_lower_case(unsigned char ch)
bool remove_field(string_view_t field_name) noexcept
Remove field by name.
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
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.
std::size_t remove_all_of(http_field_t field_id) noexcept
Remove all occurences of a field with specified 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
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