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