RESTinio
Loading...
Searching...
No Matches
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
28namespace 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*/
233enum 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.
244
245//
246// string_to_field()
247//
248
249//! Helper function to get method string name.
250//! \{
251inline http_field_t
252string_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:
288
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.
553inline 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:
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 )
609 : m_name{ field_to_string( field_id ) }
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 )
617 : m_name{ field_to_string( field_id ) }
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
647 {
648 m_field_id = field_id;
650 }
651
652 private:
653 std::string m_name;
654 std::string m_value;
656};
657
658// Make neccessary forward declarations.
660namespace impl
661{
662
663void
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 */
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
732
733 constexpr static handling_result_t stop_enumeration() noexcept
735
743
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 &
952 get_field( string_view_t field_name ) const
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 */
978 try_get_field( string_view_t field_name ) const noexcept
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 &
989 get_field( http_field_t field_id ) const
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 */
1023 try_get_field( http_field_t field_id ) const noexcept
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
1043 string_view_t field_name,
1044 string_view_t default_value ) const
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
1062 string_view_t field_name,
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
1105 http_field_t field_id,
1106 string_view_t default_value ) const
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
1151 http_field_t field_id,
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
1223 remove_all_of( string_view_t field_name ) noexcept
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
1247 remove_all_of( http_field_t field_id ) noexcept
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<
1411 handling_result_t,
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<
1467 handling_result_t,
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
1517 find( string_view_t field_name ) noexcept
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
1539 find( http_field_t field_id ) noexcept
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.
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
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.
1629 {
1631 }
1632
1633 //! Set the value of 'connection' header field.
1634 void
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{
1748 const char * m_name;
1749
1750public:
1751 static constexpr const int unknown_method = -1;
1752
1753 constexpr http_method_id_t() noexcept
1755 , m_name{ "<undefined>" }
1756 {}
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
1794inline std::ostream &
1795operator<<( std::ostream & to, const http_method_id_t & m )
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
1809inline 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{
1835public :
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.
1859struct 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:
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
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
1901
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 {
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
1969 {
1970 // If request separator hadn't already appeared,
1971 // search for it in a new block.
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() };
1984 std::string m_request_target;
1985 std::size_t m_query_separator_pos{ 0 };
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
2001 : m_status_code{ status_code }
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 */
2037template< typename CharT, typename Traits >
2038inline std::basic_ostream<CharT, Traits> &
2039operator<<(
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
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
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
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:
2143
2146 std::string reason_phrase )
2147 : m_status_code{ sc }
2148 , m_reason_phrase{ std::move( reason_phrase ) }
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:
2169 std::string m_reason_phrase;
2170};
2171
2172inline std::ostream &
2173operator << ( std::ostream & o, const http_status_line_t & status_line )
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.
2351struct http_response_header_t final
2352 : public http_header_common_t
2353{
2354 public:
2357
2359 : m_status_line{ std::move( status_line ) }
2360 {}
2361
2363 status_code() const noexcept
2364 { return m_status_line.status_code(); }
2365
2366 void
2369
2370 const std::string &
2371 reason_phrase() const noexcept
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 */
The default implementation for http_method_mapper.
static constexpr http_method_id_t from_nodejs(int value) noexcept
Exception class for all exceptions thrown by RESTinio.
Definition exception.hpp:26
exception_t(const char *err)
Definition exception.hpp:29
A single header field.
void field_id(http_field_t field_id)
http_header_field_t(std::string name, std::string value)
const std::string & value() const noexcept
const std::string & name() const noexcept
http_field_t field_id() const noexcept
http_header_field_t(http_field_t field_id, std::string value)
void append_value(string_view_t v)
bool has_field(string_view_t field_name) const noexcept
Check field by name.
string_view_t value_of(string_view_t name) const
Get the value of a field or throw if the field not found.
void add_field(http_header_field_t http_header_field)
Add a field in the form of http_header_field object.
http_header_fields_t(const http_header_fields_t &)=default
std::optional< string_view_t > opt_value_of(http_field_t field_id) const noexcept
Get optional value of a field.
void add_field(http_field_t field_id, std::string field_value)
Add a field in the form of id-value pair.
string_view_t value_of(http_field_t field_id) const
Get the value of a field or throw if the field not found.
fields_container_t::iterator find(string_view_t field_name) noexcept
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.
std::size_t remove_all_of(string_view_t field_name) noexcept
Remove all occurences of a field with specified name.
http_header_fields_t(http_header_fields_t &&)=default
static constexpr handling_result_t stop_enumeration() noexcept
void swap_fields(http_header_fields_t &http_header_fields)
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.
static constexpr handling_result_t continue_enumeration() noexcept
fields_container_t::const_iterator cfind(string_view_t field_name) const noexcept
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.
void add_field(std::string field_name, std::string field_value)
Add a field in the form of name-value pair.
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.
bool remove_field(http_field_t field_id) noexcept
Remove field by id.
http_header_fields_t & operator=(const http_header_fields_t &)=default
const std::string & get_field(http_field_t field_id) const
Get field by id.
void set_field(std::string field_name, std::string field_value)
Set field with string pair.
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.
void set_field(http_field_t field_id, std::string field_value)
Set field with id-value pair.
http_header_fields_t & operator=(http_header_fields_t &&)=default
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.
handling_result_t
The result of handling yet another field value.
@ stop_enumeration
The loop on field values should be stopped.
@ continue_enumeration
Next value of field should be found and passed to the next invocation of handler.
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 append_last_field(string_view_t field_value)
Appends last added field.
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.
void set_field(http_header_field_t http_header_field)
Set header field via http_header_field_t.
void for_each_field(Lambda &&lambda) const noexcept(noexcept(lambda(std::declval< const http_header_field_t & >())))
Enumeration of fields.
void append_field(string_view_t field_name, string_view_t field_value)
Append field with name.
std::optional< string_view_t > opt_value_of(string_view_t name) const noexcept
Get optional value of a field.
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.
const_iterator end() const noexcept
const std::string & get_field(string_view_t field_name) const
Get field by name.
auto fields_count() const noexcept
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.
const_iterator begin() const noexcept
bool remove_field(string_view_t field_name) noexcept
Remove field by name.
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.
bool has_field(http_field_t field_id) const noexcept
Check field by field-id.
fields_container_t::const_iterator cfind(http_field_t field_id) const 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.
std::size_t remove_all_of(http_field_t field_id) noexcept
Remove all occurences of a field with specified id.
fields_container_t::iterator find(http_field_t field_id) noexcept
void append_field(http_field_t field_id, string_view_t field_value)
Append field with id.
A type for representation of HTTP method ID.
friend constexpr bool operator<(const http_method_id_t &a, const http_method_id_t &b) noexcept
static constexpr const int unknown_method
constexpr http_method_id_t & operator=(http_method_id_t &&) noexcept=default
constexpr http_method_id_t(const http_method_id_t &) noexcept=default
friend constexpr bool operator!=(const http_method_id_t &a, const http_method_id_t &b) noexcept
constexpr http_method_id_t() noexcept
constexpr http_method_id_t(http_method_id_t &&) noexcept=default
constexpr auto raw_id() const noexcept
constexpr http_method_id_t & operator=(const http_method_id_t &) noexcept=default
constexpr http_method_id_t(int value, const char *name) noexcept
friend constexpr bool operator==(const http_method_id_t &a, const http_method_id_t &b) noexcept
constexpr const char * c_str() const noexcept
A handy wrapper for HTTP response status code.
constexpr auto raw_code() const noexcept
constexpr bool operator==(const http_status_code_t &sc) const noexcept
constexpr bool operator!=(const http_status_code_t &sc) const noexcept
constexpr http_status_code_t() noexcept
constexpr bool operator<(const http_status_code_t &sc) const noexcept
constexpr http_status_code_t(std::uint16_t status_code) noexcept
std::uint16_t m_status_code
Status code value.
HTTP response header status line.
void reason_phrase(std::string r)
void status_code(http_status_code_t c) noexcept
http_status_line_t(http_status_code_t sc, std::string reason_phrase)
http_status_code_t status_code() const noexcept
http_status_code_t m_status_code
const std::string & reason_phrase() const noexcept
#define RESTINIO_HTTP_METHOD_MAP(RESTINIO_GEN)
HTTP methods mapping with nodejs http methods.
#define RESTINIO_HEADER_FIELDS_DEFAULT_RESERVE_COUNT
#define RESTINIO_HTTP_FIELDS_MAP(RESTINIO_GEN)
#define RESTINIO_HTTP_CHECK_FOR_FIELD(field_id, candidate_field_name)
#define RESTINIO_FMT_FORMAT_STRING(s)
void append_last_field_accessor(http_header_fields_t &, string_view_t)
constexpr http_status_code_t switching_protocols
constexpr http_status_code_t gone
constexpr http_status_code_t precondition_failed
constexpr http_status_code_t ok
constexpr http_status_code_t unauthorized
constexpr http_status_code_t bad_request
constexpr http_status_code_t see_other
constexpr http_status_code_t multiple_choices
constexpr http_status_code_t not_acceptable
constexpr http_status_code_t not_found
constexpr http_status_code_t forbidden
constexpr http_status_code_t gateway_time_out
constexpr http_status_code_t uri_too_long
constexpr http_status_code_t partial_content
constexpr http_status_code_t requested_range_not_satisfiable
constexpr http_status_code_t unsupported_media_type
constexpr http_status_code_t locked
constexpr http_status_code_t not_implemented
constexpr http_status_code_t request_header_fields_too_large
constexpr http_status_code_t payload_too_large
constexpr http_status_code_t failed_dependency
constexpr http_status_code_t unprocessable_entity
constexpr http_status_code_t conflict
constexpr http_status_code_t network_authentication_required
constexpr http_status_code_t not_modified
constexpr http_status_code_t no_content
constexpr http_status_code_t accepted
constexpr http_status_code_t created
constexpr http_status_code_t http_version_not_supported
constexpr http_status_code_t multi_status
constexpr http_status_code_t processing
constexpr http_status_code_t bad_gateway
constexpr http_status_code_t use_proxy
constexpr http_status_code_t found
constexpr http_status_code_t continue_
constexpr http_status_code_t temporary_redirect
constexpr http_status_code_t method_not_allowed
constexpr http_status_code_t permanent_redirect
constexpr http_status_code_t length_required
constexpr http_status_code_t insufficient_storage
constexpr http_status_code_t service_unavailable
constexpr http_status_code_t precondition_required
constexpr http_status_code_t request_time_out
constexpr http_status_code_t internal_server_error
constexpr http_status_code_t too_many_requests
constexpr http_status_code_t proxy_authentication_required
constexpr http_status_code_t payment_required
constexpr http_status_code_t moved_permanently
constexpr http_status_code_t reset_content
constexpr http_status_code_t expectation_failed
constexpr http_status_code_t non_authoritative_information
http_status_line_t status_gone()
http_status_line_t status_not_acceptable()
http_status_line_t status_non_authoritative_information()
http_status_line_t status_locked()
http_status_line_t status_not_implemented()
http_status_line_t status_unprocessable_entity()
http_status_line_t status_http_version_not_supported()
http_field_t http_field
Helper alies to omitt _t suffix.
http_status_line_t status_payment_required()
http_status_line_t status_conflict()
http_status_line_t status_permanent_redirect()
http_status_line_t status_partial_content()
http_status_line_t status_no_content()
http_status_line_t status_network_authentication_required()
http_status_line_t status_not_modified()
http_status_line_t status_failed_dependency()
http_status_line_t status_moved_permanently()
http_status_line_t status_forbidden()
http_connection_header_t
Values for conection header field.
http_status_line_t status_continue()
http_status_line_t status_requested_range_not_satisfiable()
http_status_line_t status_internal_server_error()
http_status_line_t status_use_proxy()
http_status_line_t status_request_time_out()
http_status_line_t status_created()
http_status_line_t status_unauthorized()
http_status_line_t status_temporary_redirect()
http_status_line_t status_gateway_time_out()
http_status_line_t status_found()
http_status_line_t status_multiple_choices()
constexpr http_method_id_t http_method_unknown()
http_status_line_t status_insufficient_storage()
http_status_line_t status_unsupported_media_type()
http_status_line_t status_too_many_requests()
http_status_line_t status_bad_gateway()
http_status_line_t status_expectation_failed()
http_status_line_t status_see_other()
http_field_t string_to_field(string_view_t field) noexcept
Helper function to get method string name.
const char * field_to_string(http_field_t f) noexcept
Helper sunction to get method string name.
http_status_line_t status_reset_content()
http_status_line_t status_ok()
http_field_t
C++ enum that repeats nodejs c-style enum.
http_status_line_t status_switching_protocols()
http_status_line_t status_payload_too_large()
http_status_line_t status_uri_too_long()
http_status_line_t status_request_header_fields_too_large()
http_status_line_t status_processing()
http_status_line_t status_precondition_failed()
http_status_line_t status_method_not_allowed()
http_status_line_t status_accepted()
http_status_line_t status_proxy_authentication_required()
http_status_line_t status_precondition_required()
http_status_line_t status_bad_request()
http_status_line_t status_not_found()
http_status_line_t status_multi_status()
http_status_line_t status_service_unavailable()
http_status_line_t status_length_required()
Req/Resp headers common data.
void should_keep_alive(bool keep_alive) noexcept
void content_length(std::uint64_t l) noexcept
void http_major(std::uint16_t v) noexcept
bool should_keep_alive() const noexcept
http_connection_header_t m_http_connection_header_field_value
std::uint16_t http_major() const noexcept
Http version.
http_connection_header_t connection() const
Get the value of 'connection' header field.
std::uint16_t m_http_major
Http version.
std::uint64_t m_content_length
Length of body of an http-message.
std::uint64_t content_length() const noexcept
Length of body of an http-message.
void http_minor(std::uint16_t v) noexcept
std::uint16_t http_minor() const noexcept
void connection(http_connection_header_t ch) noexcept
Set the value of 'connection' header field.
void method(http_method_id_t m) noexcept
string_view_t fragment() const
Get the fragment part of the request URL.
string_view_t path() const noexcept
Request URL-structure.
const std::string & request_target() const noexcept
void append_request_target(const char *at, size_t length)
Helpfull function for using in parser callback.
static std::size_t memchr_helper(int chr, const char *from, std::size_t size)
http_method_id_t method() const noexcept
string_view_t query() const noexcept
Get the query part of the request URL.
http_request_header_t(http_method_id_t method, std::string request_target_)
void status_code(http_status_code_t c) noexcept
const http_status_line_t & status_line() const noexcept
void status_line(http_status_line_t sl)
http_status_code_t status_code() const noexcept
http_response_header_t(http_status_line_t status_line)
const std::string & reason_phrase() const noexcept