From 058c29abc15fb518c141bb8feb6d13034ba7e6e9 Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Tue, 21 Jul 2026 13:29:47 +0330 Subject: [PATCH 1/2] Curate field enum to modern HTTP fields --- include/boost/http/field.hpp | 331 ++++------------------ src/field.cpp | 526 ++++++++++------------------------- test/unit/field.cpp | 321 ++++----------------- test/unit/fields_base.cpp | 2 +- 4 files changed, 240 insertions(+), 940 deletions(-) diff --git a/include/boost/http/field.hpp b/include/boost/http/field.hpp index 31da5cf6..77698037 100644 --- a/include/boost/http/field.hpp +++ b/include/boost/http/field.hpp @@ -23,18 +23,15 @@ namespace http { */ enum class field : unsigned short { - a_im = 1, - accept, - accept_additions, - accept_charset, - accept_datetime, + accept = 1, + accept_ch, + accept_charset, // Deprecated accept_encoding, - accept_features, accept_language, accept_patch, accept_post, accept_ranges, - access_control, + accept_signature, access_control_allow_credentials, access_control_allow_headers, access_control_allow_methods, @@ -45,340 +42,116 @@ enum class field : unsigned short access_control_request_method, age, allow, - alpn, - also_control, alt_svc, alt_used, - alternate_recipient, - alternates, - apparently_to, - apply_to_redirect_ref, - approved, - archive, - archived_at, - article_names, - article_updates, - authentication_control, - authentication_info, - authentication_results, authorization, - auto_submitted, - autoforwarded, - autosubmitted, - base, - bcc, - body, - c_ext, - c_man, - c_opt, - c_pep, - c_pep_info, cache_control, - caldav_timezones, - cancel_key, - cancel_lock, - cc, - close, - comments, - compliance, + clear_site_data, connection, - content_alternative, - content_base, - content_description, + content_digest, content_disposition, - content_duration, + content_dpr, // Non-standard // Deprecated content_encoding, - content_features, - content_id, - content_identifier, content_language, content_length, content_location, - content_md5, content_range, - content_return, - content_script_type, - content_style_type, - content_transfer_encoding, + content_security_policy, + content_security_policy_report_only, content_type, - content_version, - control, - conversion, - conversion_with_loss, cookie, - cookie2, - cost, - dasl, + cross_origin_embedder_policy, + cross_origin_opener_policy, + cross_origin_resource_policy, date, - date_received, - dav, - default_style, - deferred_delivery, - delivery_date, - delta_base, - depth, - derived_from, - destination, - differential_id, + deprecation, + device_memory, digest, - discarded_x400_ipms_extensions, - discarded_x400_mts_extensions, - disclose_recipients, - disposition_notification_options, - disposition_notification_to, - distribution, - dkim_signature, - dl_expansion_history, - downgraded_bcc, - downgraded_cc, - downgraded_disposition_notification_to, - downgraded_final_recipient, - downgraded_from, - downgraded_in_reply_to, - downgraded_mail_from, - downgraded_message_id, - downgraded_original_recipient, - downgraded_rcpt_to, - downgraded_references, - downgraded_reply_to, - downgraded_resent_bcc, - downgraded_resent_cc, - downgraded_resent_from, - downgraded_resent_reply_to, - downgraded_resent_sender, - downgraded_resent_to, - downgraded_return_path, - downgraded_sender, - downgraded_to, - ediint_features, - eesst_version, - encoding, - encrypted, - errors_to, + dnt, // Non-standard // Deprecated + dpr, // Non-standard // Deprecated etag, expect, + expect_ct, // Deprecated expires, - expiry_date, - ext, - followup_to, forwarded, from, - generate_delivery_report, - getprofile, - hobareg, host, - http2_settings, - if_, + http2_settings, // Deprecated if_match, if_modified_since, if_none_match, if_range, - if_schedule_tag_match, if_unmodified_since, - im, - importance, - in_reply_to, - incomplete_copy, - injection_date, - injection_info, - jabber_id, keep_alive, - keywords, - label, - language, last_modified, - latest_delivery_time, - lines, link, - list_archive, - list_help, - list_id, - list_owner, - list_post, - list_subscribe, - list_unsubscribe, - list_unsubscribe_post, location, - lock_token, - man, max_forwards, - memento_datetime, - message_context, - message_id, - message_type, - meter, - method_check, - method_check_expires, - mime_version, - mmhs_acp127_message_identifier, - mmhs_authorizing_users, - mmhs_codress_message_indicator, - mmhs_copy_precedence, - mmhs_exempted_address, - mmhs_extended_authorisation_info, - mmhs_handling_instructions, - mmhs_message_instructions, - mmhs_message_type, - mmhs_originator_plad, - mmhs_originator_reference, - mmhs_other_recipients_indicator_cc, - mmhs_other_recipients_indicator_to, - mmhs_primary_precedence, - mmhs_subject_indicator_codes, - mt_priority, - negotiate, - newsgroups, - nntp_posting_date, - nntp_posting_host, - non_compliance, - obsoletes, - opt, - optional, - optional_www_authenticate, - ordering_type, - organization, origin, - original_encoded_information_types, - original_from, - original_message_id, - original_recipient, - original_sender, - original_subject, - originator_return_address, - overwrite, - p3p, - path, - pep, - pep_info, - pics_label, - position, - posting_version, - pragma, + origin_agent_cluster, + pragma, // Deprecated prefer, preference_applied, - prevent_nondelivery_report, priority, - privicon, - profileobject, - protocol, - protocol_info, - protocol_query, - protocol_request, proxy_authenticate, - proxy_authentication_info, proxy_authorization, proxy_connection, - proxy_features, - proxy_instruction, - public_, - public_key_pins, - public_key_pins_report_only, range, - received, - received_spf, - redirect_ref, - references, referer, - referer_root, - relay_version, - reply_by, - reply_to, - require_recipient_valid_since, - resent_bcc, - resent_cc, - resent_date, - resent_from, - resent_message_id, - resent_reply_to, - resent_sender, - resent_to, - resolution_hint, - resolver_location, + referrer_policy, + refresh, + report_to, // Non-standard // Deprecated + reporting_endpoints, + repr_digest, retry_after, - return_path, - safe, - schedule_reply, - schedule_tag, + sec_ch_ua_full_version, // Deprecated sec_fetch_dest, sec_fetch_mode, sec_fetch_site, sec_fetch_user, + sec_purpose, sec_websocket_accept, sec_websocket_extensions, sec_websocket_key, sec_websocket_protocol, sec_websocket_version, - security_scheme, - see_also, - sender, - sensitivity, server, + server_timing, + service_worker, + service_worker_allowed, + service_worker_navigation_preload, set_cookie, - set_cookie2, - setprofile, - sio_label, - sio_label_history, - slug, - soapaction, - solicitation, - status_uri, + set_login, + signature, + signature_input, + sourcemap, strict_transport_security, - subject, - subok, - subst, - summary, - supersedes, - surrogate_capability, - surrogate_control, - tcn, te, - timeout, - title, - to, - topic, + timing_allow_origin, + tk, // Non-standard // Deprecated trailer, transfer_encoding, - ttl, - ua_color, - ua_media, - ua_pixels, - ua_resolution, - ua_windowpixels, upgrade, - urgency, - uri, + upgrade_insecure_requests, user_agent, - variant_vary, vary, - vbr_info, - version, via, - want_digest, - warning, + viewport_width, // Non-standard // Deprecated + want_content_digest, + want_repr_digest, + warning, // Deprecated + width, // Non-standard // Deprecated www_authenticate, - x_archived_at, - x_device_accept, - x_device_accept_charset, - x_device_accept_encoding, - x_device_accept_language, - x_device_user_agent, + x_content_type_options, + x_dns_prefetch_control, // Non-standard + x_forwarded_for, // Non-standard + x_forwarded_host, // Non-standard + x_forwarded_proto, // Non-standard x_frame_options, - x_mittente, - x_pgp_sig, - x_ricevuta, - x_riferimento_message_id, - x_tiporicevuta, - x_trasporto, - x_verificasicurezza, - x400_content_identifier, - x400_content_return, - x400_content_type, - x400_mts_identifier, - x400_originator, - x400_received, - x400_recipients, - x400_trace, - xref + x_permitted_cross_domain_policies, // Non-standard + x_powered_by, // Non-standard + x_robots_tag, // Non-standard + x_xss_protection // Non-standard // Deprecated }; //------------------------------------------------ diff --git a/src/field.cpp b/src/field.cpp index d856eabd..202b3ed6 100644 --- a/src/field.cpp +++ b/src/field.cpp @@ -40,7 +40,7 @@ struct field_table } using array_type = std::array< - core::string_view, 357>; + core::string_view, 130>; // Strings are converted to lowercase static @@ -105,392 +105,155 @@ struct field_table array_type by_name_; - enum { N = 5155 }; - unsigned char map_[ N ][ 2 ] = {}; + enum { N = 1367 }; + unsigned char map_[ N ] = {}; /* From: - - https://www.iana.org/assignments/message-headers/message-headers.xhtml + https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers + https://www.iana.org/assignments/http-fields/http-fields.xhtml */ field_table() : by_name_({{ -// string constants -"", -"A-IM", -"Accept", -"Accept-Additions", -"Accept-Charset", -"Accept-Datetime", -"Accept-Encoding", -"Accept-Features", -"Accept-Language", -"Accept-Patch", -"Accept-Post", -"Accept-Ranges", -"Access-Control", -"Access-Control-Allow-Credentials", -"Access-Control-Allow-Headers", -"Access-Control-Allow-Methods", -"Access-Control-Allow-Origin", -"Access-Control-Expose-Headers", -"Access-Control-Max-Age", -"Access-Control-Request-Headers", -"Access-Control-Request-Method", -"Age", -"Allow", -"ALPN", -"Also-Control", -"Alt-Svc", -"Alt-Used", -"Alternate-Recipient", -"Alternates", -"Apparently-To", -"Apply-To-Redirect-Ref", -"Approved", -"Archive", -"Archived-At", -"Article-Names", -"Article-Updates", -"Authentication-Control", -"Authentication-Info", -"Authentication-Results", -"Authorization", -"Auto-Submitted", -"Autoforwarded", -"Autosubmitted", -"Base", -"Bcc", -"Body", -"C-Ext", -"C-Man", -"C-Opt", -"C-PEP", -"C-PEP-Info", -"Cache-Control", -"CalDAV-Timezones", -"Cancel-Key", -"Cancel-Lock", -"Cc", -"Close", -"Comments", -"Compliance", -"Connection", -"Content-Alternative", -"Content-Base", -"Content-Description", -"Content-Disposition", -"Content-Duration", -"Content-Encoding", -"Content-features", -"Content-ID", -"Content-Identifier", -"Content-Language", -"Content-Length", -"Content-Location", -"Content-MD5", -"Content-Range", -"Content-Return", -"Content-Script-Type", -"Content-Style-Type", -"Content-Transfer-Encoding", -"Content-Type", -"Content-Version", -"Control", -"Conversion", -"Conversion-With-Loss", -"Cookie", -"Cookie2", -"Cost", -"DASL", -"Date", -"Date-Received", -"DAV", -"Default-Style", -"Deferred-Delivery", -"Delivery-Date", -"Delta-Base", -"Depth", -"Derived-From", -"Destination", -"Differential-ID", -"Digest", -"Discarded-X400-IPMS-Extensions", -"Discarded-X400-MTS-Extensions", -"Disclose-Recipients", -"Disposition-Notification-Options", -"Disposition-Notification-To", -"Distribution", -"DKIM-Signature", -"DL-Expansion-History", -"Downgraded-Bcc", -"Downgraded-Cc", -"Downgraded-Disposition-Notification-To", -"Downgraded-Final-Recipient", -"Downgraded-From", -"Downgraded-In-Reply-To", -"Downgraded-Mail-From", -"Downgraded-Message-Id", -"Downgraded-Original-Recipient", -"Downgraded-Rcpt-To", -"Downgraded-References", -"Downgraded-Reply-To", -"Downgraded-Resent-Bcc", -"Downgraded-Resent-Cc", -"Downgraded-Resent-From", -"Downgraded-Resent-Reply-To", -"Downgraded-Resent-Sender", -"Downgraded-Resent-To", -"Downgraded-Return-Path", -"Downgraded-Sender", -"Downgraded-To", -"EDIINT-Features", -"Eesst-Version", -"Encoding", -"Encrypted", -"Errors-To", -"ETag", -"Expect", -"Expires", -"Expiry-Date", -"Ext", -"Followup-To", -"Forwarded", -"From", -"Generate-Delivery-Report", -"GetProfile", -"Hobareg", -"Host", -"HTTP2-Settings", -"If", -"If-Match", -"If-Modified-Since", -"If-None-Match", -"If-Range", -"If-Schedule-Tag-Match", -"If-Unmodified-Since", -"IM", -"Importance", -"In-Reply-To", -"Incomplete-Copy", -"Injection-Date", -"Injection-Info", -"Jabber-ID", -"Keep-Alive", -"Keywords", -"Label", -"Language", -"Last-Modified", -"Latest-Delivery-Time", -"Lines", -"Link", -"List-Archive", -"List-Help", -"List-ID", -"List-Owner", -"List-Post", -"List-Subscribe", -"List-Unsubscribe", -"List-Unsubscribe-Post", -"Location", -"Lock-Token", -"Man", -"Max-Forwards", -"Memento-Datetime", -"Message-Context", -"Message-ID", -"Message-Type", -"Meter", -"Method-Check", -"Method-Check-Expires", -"MIME-Version", -"MMHS-Acp127-Message-Identifier", -"MMHS-Authorizing-Users", -"MMHS-Codress-Message-Indicator", -"MMHS-Copy-Precedence", -"MMHS-Exempted-Address", -"MMHS-Extended-Authorisation-Info", -"MMHS-Handling-Instructions", -"MMHS-Message-Instructions", -"MMHS-Message-Type", -"MMHS-Originator-PLAD", -"MMHS-Originator-Reference", -"MMHS-Other-Recipients-Indicator-CC", -"MMHS-Other-Recipients-Indicator-To", -"MMHS-Primary-Precedence", -"MMHS-Subject-Indicator-Codes", -"MT-Priority", -"Negotiate", -"Newsgroups", -"NNTP-Posting-Date", -"NNTP-Posting-Host", -"Non-Compliance", -"Obsoletes", -"Opt", -"Optional", -"Optional-WWW-Authenticate", -"Ordering-Type", -"Organization", -"Origin", -"Original-Encoded-Information-Types", -"Original-From", -"Original-Message-ID", -"Original-Recipient", -"Original-Sender", -"Original-Subject", -"Originator-Return-Address", -"Overwrite", -"P3P", -"Path", -"PEP", -"Pep-Info", -"PICS-Label", -"Position", -"Posting-Version", -"Pragma", -"Prefer", -"Preference-Applied", -"Prevent-NonDelivery-Report", -"Priority", -"Privicon", -"ProfileObject", -"Protocol", -"Protocol-Info", -"Protocol-Query", -"Protocol-Request", -"Proxy-Authenticate", -"Proxy-Authentication-Info", -"Proxy-Authorization", -"Proxy-Connection", -"Proxy-Features", -"Proxy-Instruction", -"Public", -"Public-Key-Pins", -"Public-Key-Pins-Report-Only", -"Range", -"Received", -"Received-SPF", -"Redirect-Ref", -"References", -"Referer", -"Referer-Root", -"Relay-Version", -"Reply-By", -"Reply-To", -"Require-Recipient-Valid-Since", -"Resent-Bcc", -"Resent-Cc", -"Resent-Date", -"Resent-From", -"Resent-Message-ID", -"Resent-Reply-To", -"Resent-Sender", -"Resent-To", -"Resolution-Hint", -"Resolver-Location", -"Retry-After", -"Return-Path", -"Safe", -"Schedule-Reply", -"Schedule-Tag", -"Sec-Fetch-Dest", -"Sec-Fetch-Mode", -"Sec-Fetch-Site", -"Sec-Fetch-User", -"Sec-WebSocket-Accept", -"Sec-WebSocket-Extensions", -"Sec-WebSocket-Key", -"Sec-WebSocket-Protocol", -"Sec-WebSocket-Version", -"Security-Scheme", -"See-Also", -"Sender", -"Sensitivity", -"Server", -"Set-Cookie", -"Set-Cookie2", -"SetProfile", -"SIO-Label", -"SIO-Label-History", -"SLUG", -"SoapAction", -"Solicitation", -"Status-URI", -"Strict-Transport-Security", -"Subject", -"SubOK", -"Subst", -"Summary", -"Supersedes", -"Surrogate-Capability", -"Surrogate-Control", -"TCN", -"TE", -"Timeout", -"Title", -"To", -"Topic", -"Trailer", -"Transfer-Encoding", -"TTL", -"UA-Color", -"UA-Media", -"UA-Pixels", -"UA-Resolution", -"UA-Windowpixels", -"Upgrade", -"Urgency", -"URI", -"User-Agent", -"Variant-Vary", -"Vary", -"VBR-Info", -"Version", -"Via", -"Want-Digest", -"Warning", -"WWW-Authenticate", -"X-Archived-At", -"X-Device-Accept", -"X-Device-Accept-Charset", -"X-Device-Accept-Encoding", -"X-Device-Accept-Language", -"X-Device-User-Agent", -"X-Frame-Options", -"X-Mittente", -"X-PGP-Sig", -"X-Ricevuta", -"X-Riferimento-Message-ID", -"X-TipoRicevuta", -"X-Trasporto", -"X-VerificaSicurezza", -"X400-Content-Identifier", -"X400-Content-Return", -"X400-Content-Type", -"X400-MTS-Identifier", -"X400-Originator", -"X400-Received", -"X400-Recipients", -"X400-Trace", -"Xref" + "", + "Accept", + "Accept-CH", + "Accept-Charset", + "Accept-Encoding", + "Accept-Language", + "Accept-Patch", + "Accept-Post", + "Accept-Ranges", + "Accept-Signature", + "Access-Control-Allow-Credentials", + "Access-Control-Allow-Headers", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Origin", + "Access-Control-Expose-Headers", + "Access-Control-Max-Age", + "Access-Control-Request-Headers", + "Access-Control-Request-Method", + "Age", + "Allow", + "Alt-Svc", + "Alt-Used", + "Authorization", + "Cache-Control", + "Clear-Site-Data", + "Connection", + "Content-Digest", + "Content-Disposition", + "Content-DPR", + "Content-Encoding", + "Content-Language", + "Content-Length", + "Content-Location", + "Content-Range", + "Content-Security-Policy", + "Content-Security-Policy-Report-Only", + "Content-Type", + "Cookie", + "Cross-Origin-Embedder-Policy", + "Cross-Origin-Opener-Policy", + "Cross-Origin-Resource-Policy", + "Date", + "Deprecation", + "Device-Memory", + "Digest", + "DNT", + "DPR", + "ETag", + "Expect", + "Expect-CT", + "Expires", + "Forwarded", + "From", + "Host", + "HTTP2-Settings", + "If-Match", + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Keep-Alive", + "Last-Modified", + "Link", + "Location", + "Max-Forwards", + "Origin", + "Origin-Agent-Cluster", + "Pragma", + "Prefer", + "Preference-Applied", + "Priority", + "Proxy-Authenticate", + "Proxy-Authorization", + "Proxy-Connection", + "Range", + "Referer", + "Referrer-Policy", + "Refresh", + "Report-To", + "Reporting-Endpoints", + "Repr-Digest", + "Retry-After", + "Sec-CH-UA-Full-Version", + "Sec-Fetch-Dest", + "Sec-Fetch-Mode", + "Sec-Fetch-Site", + "Sec-Fetch-User", + "Sec-Purpose", + "Sec-WebSocket-Accept", + "Sec-WebSocket-Extensions", + "Sec-WebSocket-Key", + "Sec-WebSocket-Protocol", + "Sec-WebSocket-Version", + "Server", + "Server-Timing", + "Service-Worker", + "Service-Worker-Allowed", + "Service-Worker-Navigation-Preload", + "Set-Cookie", + "Set-Login", + "Signature", + "Signature-Input", + "SourceMap", + "Strict-Transport-Security", + "TE", + "Timing-Allow-Origin", + "Tk", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Upgrade-Insecure-Requests", + "User-Agent", + "Vary", + "Via", + "Viewport-Width", + "Want-Content-Digest", + "Want-Repr-Digest", + "Warning", + "Width", + "WWW-Authenticate", + "X-Content-Type-Options", + "X-DNS-Prefetch-Control", + "X-Forwarded-For", + "X-Forwarded-Host", + "X-Forwarded-Proto", + "X-Frame-Options", + "X-Permitted-Cross-Domain-Policies", + "X-Powered-By", + "X-Robots-Tag", + "X-XSS-Protection" }}) { - for(std::size_t i = 1, n = 256; i < n; ++i) + for(std::size_t i = 1; i < by_name_.size(); ++i) { auto sv = by_name_[ i ]; auto h = digest(sv); auto j = h % N; - BOOST_ASSERT(map_[j][0] == 0); - map_[j][0] = static_cast(i); - } - - for(std::size_t i = 256, n = by_name_.size(); i < n; ++i) - { - auto sv = by_name_[i]; - auto h = digest(sv); - auto j = h % N; - BOOST_ASSERT(map_[j][1] == 0); - map_[j][1] = static_cast(i - 255); + BOOST_ASSERT(map_[j] == 0); + map_[j] = static_cast(i); } } @@ -500,17 +263,8 @@ struct field_table { auto h = digest(s); auto j = h % N; - int i = map_[j][0]; - core::string_view s2 = by_name_[i]; - if(i != 0 && equals(s, s2)) - return static_cast(i); - i = map_[j][1]; - if(i == 0) - return boost::none; - i += 255; - s2 = by_name_[i]; - - if(equals(s, s2)) + int i = map_[j]; + if(i != 0 && equals(s, by_name_[i])) return static_cast(i); return boost::none; } diff --git a/test/unit/field.cpp b/test/unit/field.cpp index 9018b04d..a2a37273 100644 --- a/test/unit/field.cpp +++ b/test/unit/field.cpp @@ -36,18 +36,15 @@ class field_test match(field::accept, "aCcept"); match(field::accept, "ACCEPT"); - match(field::a_im, "A-IM"); match(field::accept, "Accept"); - match(field::accept_additions, "Accept-Additions"); + match(field::accept_ch, "Accept-CH"); match(field::accept_charset, "Accept-Charset"); - match(field::accept_datetime, "Accept-Datetime"); match(field::accept_encoding, "Accept-Encoding"); - match(field::accept_features, "Accept-Features"); match(field::accept_language, "Accept-Language"); match(field::accept_patch, "Accept-Patch"); match(field::accept_post, "Accept-Post"); match(field::accept_ranges, "Accept-Ranges"); - match(field::access_control, "Access-Control"); + match(field::accept_signature, "Accept-Signature"); match(field::access_control_allow_credentials, "Access-Control-Allow-Credentials"); match(field::access_control_allow_headers, "Access-Control-Allow-Headers"); match(field::access_control_allow_methods, "Access-Control-Allow-Methods"); @@ -58,340 +55,116 @@ class field_test match(field::access_control_request_method, "Access-Control-Request-Method"); match(field::age, "Age"); match(field::allow, "Allow"); - match(field::alpn, "ALPN"); - match(field::also_control, "Also-Control"); match(field::alt_svc, "Alt-Svc"); match(field::alt_used, "Alt-Used"); - match(field::alternate_recipient, "Alternate-Recipient"); - match(field::alternates, "Alternates"); - match(field::apparently_to, "Apparently-To"); - match(field::apply_to_redirect_ref, "Apply-To-Redirect-Ref"); - match(field::approved, "Approved"); - match(field::archive, "Archive"); - match(field::archived_at, "Archived-At"); - match(field::article_names, "Article-Names"); - match(field::article_updates, "Article-Updates"); - match(field::authentication_control, "Authentication-Control"); - match(field::authentication_info, "Authentication-Info"); - match(field::authentication_results, "Authentication-Results"); match(field::authorization, "Authorization"); - match(field::auto_submitted, "Auto-Submitted"); - match(field::autoforwarded, "Autoforwarded"); - match(field::autosubmitted, "Autosubmitted"); - match(field::base, "Base"); - match(field::bcc, "Bcc"); - match(field::body, "Body"); - match(field::c_ext, "C-Ext"); - match(field::c_man, "C-Man"); - match(field::c_opt, "C-Opt"); - match(field::c_pep, "C-PEP"); - match(field::c_pep_info, "C-PEP-Info"); match(field::cache_control, "Cache-Control"); - match(field::caldav_timezones, "CalDAV-Timezones"); - match(field::cancel_key, "Cancel-Key"); - match(field::cancel_lock, "Cancel-Lock"); - match(field::cc, "Cc"); - match(field::close, "Close"); - match(field::comments, "Comments"); - match(field::compliance, "Compliance"); + match(field::clear_site_data, "Clear-Site-Data"); match(field::connection, "Connection"); - match(field::content_alternative, "Content-Alternative"); - match(field::content_base, "Content-Base"); - match(field::content_description, "Content-Description"); + match(field::content_digest, "Content-Digest"); match(field::content_disposition, "Content-Disposition"); - match(field::content_duration, "Content-Duration"); + match(field::content_dpr, "Content-DPR"); match(field::content_encoding, "Content-Encoding"); - match(field::content_features, "Content-features"); - match(field::content_id, "Content-ID"); - match(field::content_identifier, "Content-Identifier"); match(field::content_language, "Content-Language"); match(field::content_length, "Content-Length"); match(field::content_location, "Content-Location"); - match(field::content_md5, "Content-MD5"); match(field::content_range, "Content-Range"); - match(field::content_return, "Content-Return"); - match(field::content_script_type, "Content-Script-Type"); - match(field::content_style_type, "Content-Style-Type"); - match(field::content_transfer_encoding, "Content-Transfer-Encoding"); + match(field::content_security_policy, "Content-Security-Policy"); + match(field::content_security_policy_report_only, "Content-Security-Policy-Report-Only"); match(field::content_type, "Content-Type"); - match(field::content_version, "Content-Version"); - match(field::control, "Control"); - match(field::conversion, "Conversion"); - match(field::conversion_with_loss, "Conversion-With-Loss"); match(field::cookie, "Cookie"); - match(field::cookie2, "Cookie2"); - match(field::cost, "Cost"); - match(field::dasl, "DASL"); + match(field::cross_origin_embedder_policy, "Cross-Origin-Embedder-Policy"); + match(field::cross_origin_opener_policy, "Cross-Origin-Opener-Policy"); + match(field::cross_origin_resource_policy, "Cross-Origin-Resource-Policy"); match(field::date, "Date"); - match(field::date_received, "Date-Received"); - match(field::dav, "DAV"); - match(field::default_style, "Default-Style"); - match(field::deferred_delivery, "Deferred-Delivery"); - match(field::delivery_date, "Delivery-Date"); - match(field::delta_base, "Delta-Base"); - match(field::depth, "Depth"); - match(field::derived_from, "Derived-From"); - match(field::destination, "Destination"); - match(field::differential_id, "Differential-ID"); + match(field::deprecation, "Deprecation"); + match(field::device_memory, "Device-Memory"); match(field::digest, "Digest"); - match(field::discarded_x400_ipms_extensions, "Discarded-X400-IPMS-Extensions"); - match(field::discarded_x400_mts_extensions, "Discarded-X400-MTS-Extensions"); - match(field::disclose_recipients, "Disclose-Recipients"); - match(field::disposition_notification_options, "Disposition-Notification-Options"); - match(field::disposition_notification_to, "Disposition-Notification-To"); - match(field::distribution, "Distribution"); - match(field::dkim_signature, "DKIM-Signature"); - match(field::dl_expansion_history, "DL-Expansion-History"); - match(field::downgraded_bcc, "Downgraded-Bcc"); - match(field::downgraded_cc, "Downgraded-Cc"); - match(field::downgraded_disposition_notification_to, "Downgraded-Disposition-Notification-To"); - match(field::downgraded_final_recipient, "Downgraded-Final-Recipient"); - match(field::downgraded_from, "Downgraded-From"); - match(field::downgraded_in_reply_to, "Downgraded-In-Reply-To"); - match(field::downgraded_mail_from, "Downgraded-Mail-From"); - match(field::downgraded_message_id, "Downgraded-Message-Id"); - match(field::downgraded_original_recipient, "Downgraded-Original-Recipient"); - match(field::downgraded_rcpt_to, "Downgraded-Rcpt-To"); - match(field::downgraded_references, "Downgraded-References"); - match(field::downgraded_reply_to, "Downgraded-Reply-To"); - match(field::downgraded_resent_bcc, "Downgraded-Resent-Bcc"); - match(field::downgraded_resent_cc, "Downgraded-Resent-Cc"); - match(field::downgraded_resent_from, "Downgraded-Resent-From"); - match(field::downgraded_resent_reply_to, "Downgraded-Resent-Reply-To"); - match(field::downgraded_resent_sender, "Downgraded-Resent-Sender"); - match(field::downgraded_resent_to, "Downgraded-Resent-To"); - match(field::downgraded_return_path, "Downgraded-Return-Path"); - match(field::downgraded_sender, "Downgraded-Sender"); - match(field::downgraded_to, "Downgraded-To"); - match(field::ediint_features, "EDIINT-Features"); - match(field::eesst_version, "Eesst-Version"); - match(field::encoding, "Encoding"); - match(field::encrypted, "Encrypted"); - match(field::errors_to, "Errors-To"); + match(field::dnt, "DNT"); + match(field::dpr, "DPR"); match(field::etag, "ETag"); match(field::expect, "Expect"); + match(field::expect_ct, "Expect-CT"); match(field::expires, "Expires"); - match(field::expiry_date, "Expiry-Date"); - match(field::ext, "Ext"); - match(field::followup_to, "Followup-To"); match(field::forwarded, "Forwarded"); match(field::from, "From"); - match(field::generate_delivery_report, "Generate-Delivery-Report"); - match(field::getprofile, "GetProfile"); - match(field::hobareg, "Hobareg"); match(field::host, "Host"); match(field::http2_settings, "HTTP2-Settings"); - match(field::if_, "If"); match(field::if_match, "If-Match"); match(field::if_modified_since, "If-Modified-Since"); match(field::if_none_match, "If-None-Match"); match(field::if_range, "If-Range"); - match(field::if_schedule_tag_match, "If-Schedule-Tag-Match"); match(field::if_unmodified_since, "If-Unmodified-Since"); - match(field::im, "IM"); - match(field::importance, "Importance"); - match(field::in_reply_to, "In-Reply-To"); - match(field::incomplete_copy, "Incomplete-Copy"); - match(field::injection_date, "Injection-Date"); - match(field::injection_info, "Injection-Info"); - match(field::jabber_id, "Jabber-ID"); match(field::keep_alive, "Keep-Alive"); - match(field::keywords, "Keywords"); - match(field::label, "Label"); - match(field::language, "Language"); match(field::last_modified, "Last-Modified"); - match(field::latest_delivery_time, "Latest-Delivery-Time"); - match(field::lines, "Lines"); match(field::link, "Link"); - match(field::list_archive, "List-Archive"); - match(field::list_help, "List-Help"); - match(field::list_id, "List-ID"); - match(field::list_owner, "List-Owner"); - match(field::list_post, "List-Post"); - match(field::list_subscribe, "List-Subscribe"); - match(field::list_unsubscribe, "List-Unsubscribe"); - match(field::list_unsubscribe_post, "List-Unsubscribe-Post"); match(field::location, "Location"); - match(field::lock_token, "Lock-Token"); - match(field::man, "Man"); match(field::max_forwards, "Max-Forwards"); - match(field::memento_datetime, "Memento-Datetime"); - match(field::message_context, "Message-Context"); - match(field::message_id, "Message-ID"); - match(field::message_type, "Message-Type"); - match(field::meter, "Meter"); - match(field::method_check, "Method-Check"); - match(field::method_check_expires, "Method-Check-Expires"); - match(field::mime_version, "MIME-Version"); - match(field::mmhs_acp127_message_identifier, "MMHS-Acp127-Message-Identifier"); - match(field::mmhs_authorizing_users, "MMHS-Authorizing-Users"); - match(field::mmhs_codress_message_indicator, "MMHS-Codress-Message-Indicator"); - match(field::mmhs_copy_precedence, "MMHS-Copy-Precedence"); - match(field::mmhs_exempted_address, "MMHS-Exempted-Address"); - match(field::mmhs_extended_authorisation_info, "MMHS-Extended-Authorisation-Info"); - match(field::mmhs_handling_instructions, "MMHS-Handling-Instructions"); - match(field::mmhs_message_instructions, "MMHS-Message-Instructions"); - match(field::mmhs_message_type, "MMHS-Message-Type"); - match(field::mmhs_originator_plad, "MMHS-Originator-PLAD"); - match(field::mmhs_originator_reference, "MMHS-Originator-Reference"); - match(field::mmhs_other_recipients_indicator_cc, "MMHS-Other-Recipients-Indicator-CC"); - match(field::mmhs_other_recipients_indicator_to, "MMHS-Other-Recipients-Indicator-To"); - match(field::mmhs_primary_precedence, "MMHS-Primary-Precedence"); - match(field::mmhs_subject_indicator_codes, "MMHS-Subject-Indicator-Codes"); - match(field::mt_priority, "MT-Priority"); - match(field::negotiate, "Negotiate"); - match(field::newsgroups, "Newsgroups"); - match(field::nntp_posting_date, "NNTP-Posting-Date"); - match(field::nntp_posting_host, "NNTP-Posting-Host"); - match(field::non_compliance, "Non-Compliance"); - match(field::obsoletes, "Obsoletes"); - match(field::opt, "Opt"); - match(field::optional, "Optional"); - match(field::optional_www_authenticate, "Optional-WWW-Authenticate"); - match(field::ordering_type, "Ordering-Type"); - match(field::organization, "Organization"); match(field::origin, "Origin"); - match(field::original_encoded_information_types, "Original-Encoded-Information-Types"); - match(field::original_from, "Original-From"); - match(field::original_message_id, "Original-Message-ID"); - match(field::original_recipient, "Original-Recipient"); - match(field::original_sender, "Original-Sender"); - match(field::original_subject, "Original-Subject"); - match(field::originator_return_address, "Originator-Return-Address"); - match(field::overwrite, "Overwrite"); - match(field::p3p, "P3P"); - match(field::path, "Path"); - match(field::pep, "PEP"); - match(field::pep_info, "Pep-Info"); - match(field::pics_label, "PICS-Label"); - match(field::position, "Position"); - match(field::posting_version, "Posting-Version"); + match(field::origin_agent_cluster, "Origin-Agent-Cluster"); match(field::pragma, "Pragma"); match(field::prefer, "Prefer"); match(field::preference_applied, "Preference-Applied"); - match(field::prevent_nondelivery_report, "Prevent-NonDelivery-Report"); match(field::priority, "Priority"); - match(field::privicon, "Privicon"); - match(field::profileobject, "ProfileObject"); - match(field::protocol, "Protocol"); - match(field::protocol_info, "Protocol-Info"); - match(field::protocol_query, "Protocol-Query"); - match(field::protocol_request, "Protocol-Request"); match(field::proxy_authenticate, "Proxy-Authenticate"); - match(field::proxy_authentication_info, "Proxy-Authentication-Info"); match(field::proxy_authorization, "Proxy-Authorization"); match(field::proxy_connection, "Proxy-Connection"); - match(field::proxy_features, "Proxy-Features"); - match(field::proxy_instruction, "Proxy-Instruction"); - match(field::public_, "Public"); - match(field::public_key_pins, "Public-Key-Pins"); - match(field::public_key_pins_report_only, "Public-Key-Pins-Report-Only"); match(field::range, "Range"); - match(field::received, "Received"); - match(field::received_spf, "Received-SPF"); - match(field::redirect_ref, "Redirect-Ref"); - match(field::references, "References"); match(field::referer, "Referer"); - match(field::referer_root, "Referer-Root"); - match(field::relay_version, "Relay-Version"); - match(field::reply_by, "Reply-By"); - match(field::reply_to, "Reply-To"); - match(field::require_recipient_valid_since, "Require-Recipient-Valid-Since"); - match(field::resent_bcc, "Resent-Bcc"); - match(field::resent_cc, "Resent-Cc"); - match(field::resent_date, "Resent-Date"); - match(field::resent_from, "Resent-From"); - match(field::resent_message_id, "Resent-Message-ID"); - match(field::resent_reply_to, "Resent-Reply-To"); - match(field::resent_sender, "Resent-Sender"); - match(field::resent_to, "Resent-To"); - match(field::resolution_hint, "Resolution-Hint"); - match(field::resolver_location, "Resolver-Location"); + match(field::referrer_policy, "Referrer-Policy"); + match(field::refresh, "Refresh"); + match(field::report_to, "Report-To"); + match(field::reporting_endpoints, "Reporting-Endpoints"); + match(field::repr_digest, "Repr-Digest"); match(field::retry_after, "Retry-After"); - match(field::return_path, "Return-Path"); - match(field::safe, "Safe"); - match(field::schedule_reply, "Schedule-Reply"); - match(field::schedule_tag, "Schedule-Tag"); + match(field::sec_ch_ua_full_version, "Sec-CH-UA-Full-Version"); match(field::sec_fetch_dest, "Sec-Fetch-Dest"); match(field::sec_fetch_mode, "Sec-Fetch-Mode"); match(field::sec_fetch_site, "Sec-Fetch-Site"); match(field::sec_fetch_user, "Sec-Fetch-User"); + match(field::sec_purpose, "Sec-Purpose"); match(field::sec_websocket_accept, "Sec-WebSocket-Accept"); match(field::sec_websocket_extensions, "Sec-WebSocket-Extensions"); match(field::sec_websocket_key, "Sec-WebSocket-Key"); match(field::sec_websocket_protocol, "Sec-WebSocket-Protocol"); match(field::sec_websocket_version, "Sec-WebSocket-Version"); - match(field::security_scheme, "Security-Scheme"); - match(field::see_also, "See-Also"); - match(field::sender, "Sender"); - match(field::sensitivity, "Sensitivity"); match(field::server, "Server"); + match(field::server_timing, "Server-Timing"); + match(field::service_worker, "Service-Worker"); + match(field::service_worker_allowed, "Service-Worker-Allowed"); + match(field::service_worker_navigation_preload, "Service-Worker-Navigation-Preload"); match(field::set_cookie, "Set-Cookie"); - match(field::set_cookie2, "Set-Cookie2"); - match(field::setprofile, "SetProfile"); - match(field::sio_label, "SIO-Label"); - match(field::sio_label_history, "SIO-Label-History"); - match(field::slug, "SLUG"); - match(field::soapaction, "SoapAction"); - match(field::solicitation, "Solicitation"); - match(field::status_uri, "Status-URI"); + match(field::set_login, "Set-Login"); + match(field::signature, "Signature"); + match(field::signature_input, "Signature-Input"); + match(field::sourcemap, "SourceMap"); match(field::strict_transport_security, "Strict-Transport-Security"); - match(field::subject, "Subject"); - match(field::subok, "SubOK"); - match(field::subst, "Subst"); - match(field::summary, "Summary"); - match(field::supersedes, "Supersedes"); - match(field::surrogate_capability, "Surrogate-Capability"); - match(field::surrogate_control, "Surrogate-Control"); - match(field::tcn, "TCN"); match(field::te, "TE"); - match(field::timeout, "Timeout"); - match(field::title, "Title"); - match(field::to, "To"); - match(field::topic, "Topic"); + match(field::timing_allow_origin, "Timing-Allow-Origin"); + match(field::tk, "Tk"); match(field::trailer, "Trailer"); match(field::transfer_encoding, "Transfer-Encoding"); - match(field::ttl, "TTL"); - match(field::ua_color, "UA-Color"); - match(field::ua_media, "UA-Media"); - match(field::ua_pixels, "UA-Pixels"); - match(field::ua_resolution, "UA-Resolution"); - match(field::ua_windowpixels, "UA-Windowpixels"); match(field::upgrade, "Upgrade"); - match(field::urgency, "Urgency"); - match(field::uri, "URI"); + match(field::upgrade_insecure_requests, "Upgrade-Insecure-Requests"); match(field::user_agent, "User-Agent"); - match(field::variant_vary, "Variant-Vary"); match(field::vary, "Vary"); - match(field::vbr_info, "VBR-Info"); - match(field::version, "Version"); match(field::via, "Via"); - match(field::want_digest, "Want-Digest"); + match(field::viewport_width, "Viewport-Width"); + match(field::want_content_digest, "Want-Content-Digest"); + match(field::want_repr_digest, "Want-Repr-Digest"); match(field::warning, "Warning"); + match(field::width, "Width"); match(field::www_authenticate, "WWW-Authenticate"); - match(field::x_archived_at, "X-Archived-At"); - match(field::x_device_accept, "X-Device-Accept"); - match(field::x_device_accept_charset, "X-Device-Accept-Charset"); - match(field::x_device_accept_encoding, "X-Device-Accept-Encoding"); - match(field::x_device_accept_language, "X-Device-Accept-Language"); - match(field::x_device_user_agent, "X-Device-User-Agent"); + match(field::x_content_type_options, "X-Content-Type-Options"); + match(field::x_dns_prefetch_control, "X-DNS-Prefetch-Control"); + match(field::x_forwarded_for, "X-Forwarded-For"); + match(field::x_forwarded_host, "X-Forwarded-Host"); + match(field::x_forwarded_proto, "X-Forwarded-Proto"); match(field::x_frame_options, "X-Frame-Options"); - match(field::x_mittente, "X-Mittente"); - match(field::x_pgp_sig, "X-PGP-Sig"); - match(field::x_ricevuta, "X-Ricevuta"); - match(field::x_riferimento_message_id, "X-Riferimento-Message-ID"); - match(field::x_tiporicevuta, "X-TipoRicevuta"); - match(field::x_trasporto, "X-Trasporto"); - match(field::x_verificasicurezza, "X-VerificaSicurezza"); - match(field::x400_content_identifier, "X400-Content-Identifier"); - match(field::x400_content_return, "X400-Content-Return"); - match(field::x400_content_type, "X400-Content-Type"); - match(field::x400_mts_identifier, "X400-MTS-Identifier"); - match(field::x400_originator, "X400-Originator"); - match(field::x400_received, "X400-Received"); - match(field::x400_recipients, "X400-Recipients"); - match(field::x400_trace, "X400-Trace"); - match(field::xref, "Xref"); + match(field::x_permitted_cross_domain_policies, "X-Permitted-Cross-Domain-Policies"); + match(field::x_powered_by, "X-Powered-By"); + match(field::x_robots_tag, "X-Robots-Tag"); + match(field::x_xss_protection, "X-XSS-Protection"); auto const unknown = [&](core::string_view s) diff --git a/test/unit/fields_base.cpp b/test/unit/fields_base.cpp index 846d51d9..f2be171f 100644 --- a/test/unit/fields_base.cpp +++ b/test/unit/fields_base.cpp @@ -1689,7 +1689,7 @@ struct fields_base_test BOOST_TEST(f.value_or( field::set_cookie, "") == "a"); BOOST_TEST(f.value_or( - field::set_cookie2, "Q") == "Q"); + field::range, "Q") == "Q"); BOOST_TEST(f.value_or( "set-cookie", "") == "a"); From df973f30908114e3e1ca0c65510a54929436600e Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Tue, 21 Jul 2026 13:49:22 +0330 Subject: [PATCH 2/2] Sync capy changes --- include/boost/http/detail/circular_buffer.hpp | 207 ++++++++++++++++++ include/boost/http/detail/flat_buffer.hpp | 206 +++++++++++++++++ src/config.cpp | 2 +- src/detail/circular_buffer.cpp | 95 ++++++++ src/detail/filter.cpp | 10 +- src/parser.cpp | 13 +- src/serializer.cpp | 6 +- test/unit/parser.cpp | 1 - test/unit/serializer.cpp | 12 +- 9 files changed, 530 insertions(+), 22 deletions(-) create mode 100644 include/boost/http/detail/circular_buffer.hpp create mode 100644 include/boost/http/detail/flat_buffer.hpp create mode 100644 src/detail/circular_buffer.cpp diff --git a/include/boost/http/detail/circular_buffer.hpp b/include/boost/http/detail/circular_buffer.hpp new file mode 100644 index 00000000..e63baba9 --- /dev/null +++ b/include/boost/http/detail/circular_buffer.hpp @@ -0,0 +1,207 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/http +// + +#ifndef BOOST_HTTP_DETAIL_CIRCULAR_BUFFER_HPP +#define BOOST_HTTP_DETAIL_CIRCULAR_BUFFER_HPP + +#include +#include + +#include + +#include +#include + +namespace boost { +namespace http { +namespace detail { + +/** A fixed-capacity circular buffer satisfying DynamicBuffer. + + This class implements a circular ( ring ) buffer with + fixed capacity determined at construction. Unlike linear + buffers, data can wrap around from the end to the beginning, + enabling efficient FIFO operations without memory copies. + + Buffer sequences returned from @ref data and @ref prepare + may contain up to two elements to represent wrapped regions. + + @par Example + @code + char storage[1024]; + circular_buffer cb( storage, sizeof( storage ) ); + + // Write data + auto mb = cb.prepare( 100 ); + std::memcpy( mb.data(), "hello", 5 ); + cb.commit( 5 ); + + // Read data + auto cb_data = cb.data(); + // process cb_data... + cb.consume( 5 ); + @endcode + + @par Thread Safety + Distinct objects: Safe. + Shared objects: Unsafe. +*/ +class circular_buffer +{ + unsigned char* base_ = nullptr; + std::size_t cap_ = 0; + std::size_t in_pos_ = 0; + std::size_t in_len_ = 0; + std::size_t out_size_ = 0; + +public: + /// Indicates this is a DynamicBuffer adapter over external storage. + using is_circular_buffer_adapter = void; + + /// The ConstBufferSequence type for readable bytes. + using const_buffers_type = std::array; + + /// The MutableBufferSequence type for writable bytes. + using mutable_buffers_type = std::array; + + /// Construct an empty circular buffer with zero capacity. + circular_buffer() = default; + + /** Construct a copy. + + Copies the adapter state (position and length) but does + not deep-copy the backing storage. Both objects alias the + same external buffer. + + @note The underlying storage must outlive all copies. + */ + circular_buffer( + circular_buffer const&) = default; + + /** Construct a circular buffer over existing storage. + + @param base Pointer to the storage. + @param capacity Size of the storage in bytes. + */ + circular_buffer( + void* base, + std::size_t capacity) noexcept + : base_(static_cast< + unsigned char*>(base)) + , cap_(capacity) + { + } + + /** Construct a circular buffer with initial readable bytes. + + @param base Pointer to the storage. + @param capacity Size of the storage in bytes. + @param initial_size Number of bytes already present as + readable. Must not exceed @p capacity. + + @throws std::invalid_argument if initial_size > capacity. + */ + circular_buffer( + void* base, + std::size_t capacity, + std::size_t initial_size) + : base_(static_cast< + unsigned char*>(base)) + , cap_(capacity) + , in_len_(initial_size) + { + if(in_len_ > capacity) + detail::throw_invalid_argument(); + } + + /** Assign by copying. + + Copies the adapter state but does not deep-copy the + backing storage. Both objects alias the same external + buffer afterward. + + @note The underlying storage must outlive all copies. + */ + circular_buffer& operator=( + circular_buffer const&) = default; + + /// Return the number of readable bytes. + std::size_t + size() const noexcept + { + return in_len_; + } + + /// Return the maximum number of bytes the buffer can hold. + std::size_t + max_size() const noexcept + { + return cap_; + } + + /// Return the number of writable bytes without reallocation. + std::size_t + capacity() const noexcept + { + return cap_ - in_len_; + } + + /// Return a buffer sequence representing the readable bytes. + BOOST_HTTP_DECL + const_buffers_type + data() const noexcept; + + /** Return a buffer sequence for writing. + + Invalidates buffer sequences previously obtained + from @ref prepare. + + @param n The desired number of writable bytes. + + @return A mutable buffer sequence of size @p n. + + @throws std::length_error if `size() + n > max_size()`. + */ + BOOST_HTTP_DECL + mutable_buffers_type + prepare(std::size_t n); + + /** Move bytes from the output to the input sequence. + + Invalidates buffer sequences previously obtained + from @ref prepare. Buffer sequences from @ref data + remain valid. + + @param n The number of bytes to commit. If greater + than the prepared size, all prepared bytes + are committed. + */ + BOOST_HTTP_DECL + void + commit(std::size_t n) noexcept; + + /** Remove bytes from the beginning of the input sequence. + + Invalidates buffer sequences previously obtained + from @ref data. Buffer sequences from @ref prepare + remain valid. + + @param n The number of bytes to consume. If greater + than @ref size(), all readable bytes are consumed. + */ + BOOST_HTTP_DECL + void + consume(std::size_t n) noexcept; +}; + +} // detail +} // http +} // boost + +#endif diff --git a/include/boost/http/detail/flat_buffer.hpp b/include/boost/http/detail/flat_buffer.hpp new file mode 100644 index 00000000..a638d8e4 --- /dev/null +++ b/include/boost/http/detail/flat_buffer.hpp @@ -0,0 +1,206 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/http +// + +#ifndef BOOST_HTTP_DETAIL_FLAT_BUFFER_HPP +#define BOOST_HTTP_DETAIL_FLAT_BUFFER_HPP + +#include +#include + +#include + +#include + +namespace boost { +namespace http { +namespace detail { + +/** A fixed-capacity linear buffer satisfying DynamicBuffer. + + This class provides a contiguous buffer with fixed capacity + determined at construction. Buffer sequences returned from + @ref data and @ref prepare always contain exactly one element, + making it suitable for APIs requiring contiguous memory. + + @par Example + @code + char storage[1024]; + flat_buffer fb( storage, sizeof( storage ) ); + + // Write data + auto mb = fb.prepare( 100 ); + std::memcpy( mb.data(), "hello", 5 ); + fb.commit( 5 ); + + // Read data + auto data = fb.data(); + // process data... + fb.consume( 5 ); + @endcode + + @par Thread Safety + Distinct objects: Safe. + Shared objects: Unsafe. + + @see circular_buffer +*/ +class flat_buffer +{ + unsigned char* data_ = nullptr; + std::size_t cap_ = 0; + std::size_t in_pos_ = 0; + std::size_t in_size_ = 0; + std::size_t out_size_ = 0; + +public: + /// Indicates this is a DynamicBuffer adapter over external storage. + using is_circular_buffer_adapter = void; + + /// The ConstBufferSequence type for readable bytes. + using const_buffers_type = capy::const_buffer; + + /// The MutableBufferSequence type for writable bytes. + using mutable_buffers_type = capy::mutable_buffer; + + /// Construct an empty flat buffer with zero capacity. + flat_buffer() = default; + + /** Construct a flat buffer over existing storage. + + @param data Pointer to the storage. + @param capacity Size of the storage in bytes. + @param initial_size Number of bytes already present as + readable. Must not exceed @p capacity. + + @throws std::invalid_argument if initial_size > capacity. + */ + flat_buffer( + void* data, + std::size_t capacity, + std::size_t initial_size = 0) + : data_(static_cast< + unsigned char*>(data)) + , cap_(capacity) + , in_size_(initial_size) + { + if(in_size_ > cap_) + detail::throw_invalid_argument(); + } + + /// Construct a copy. + flat_buffer( + flat_buffer const&) = default; + + /// Assign by copying. + flat_buffer& operator=( + flat_buffer const&) = default; + + /// Return the number of readable bytes. + std::size_t + size() const noexcept + { + return in_size_; + } + + /// Return the maximum number of bytes the buffer can hold. + std::size_t + max_size() const noexcept + { + return cap_; + } + + /// Return the number of writable bytes without reallocation. + std::size_t + capacity() const noexcept + { + return cap_ - (in_pos_ + in_size_); + } + + /// Return a buffer sequence representing the readable bytes. + const_buffers_type + data() const noexcept + { + return const_buffers_type( + data_ + in_pos_, in_size_); + } + + /** Return a buffer sequence for writing. + + Invalidates buffer sequences previously obtained + from @ref prepare. + + @param n The desired number of writable bytes. + + @return A mutable buffer sequence of size @p n. + + @throws std::invalid_argument if `n > capacity()`. + */ + mutable_buffers_type + prepare(std::size_t n) + { + if( n > capacity() ) + detail::throw_invalid_argument(); + + out_size_ = n; + return mutable_buffers_type( + data_ + in_pos_ + in_size_, n); + } + + /** Move bytes from the output to the input sequence. + + Invalidates buffer sequences previously obtained + from @ref prepare. Buffer sequences from @ref data + remain valid. + + @param n The number of bytes to commit. If greater + than the prepared size, all prepared bytes + are committed. + */ + void + commit( + std::size_t n) noexcept + { + if(n < out_size_) + in_size_ += n; + else + in_size_ += out_size_; + out_size_ = 0; + } + + /** Remove bytes from the beginning of the input sequence. + + Invalidates buffer sequences previously obtained + from @ref data. Buffer sequences from @ref prepare + remain valid. + + @param n The number of bytes to consume. If greater + than @ref size(), all readable bytes are consumed. + */ + void + consume( + std::size_t n) noexcept + { + if(n < in_size_) + { + in_pos_ += n; + in_size_ -= n; + } + else + { + in_pos_ = 0; + in_size_ = 0; + } + } +}; + +} // detail +} // http +} // boost + +#endif diff --git a/src/config.cpp b/src/config.cpp index cc789176..3e02ed1e 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -35,7 +35,7 @@ make_parser_config(parser_config cfg) /* | fb | cb0 | cb1 | T | f | - fb flat_dynamic_buffer headers.max_size + fb flat_buffer headers.max_size cb0 circular_buffer min_buffer cb1 circular_buffer min_buffer f table max_table_space diff --git a/src/detail/circular_buffer.cpp b/src/detail/circular_buffer.cpp new file mode 100644 index 00000000..9b95bfe6 --- /dev/null +++ b/src/detail/circular_buffer.cpp @@ -0,0 +1,95 @@ +// +// Copyright (c) 2023 Vinnie Falco (vinnie.falco@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/http +// + +#include +#include + +namespace boost { +namespace http { +namespace detail { + +auto +circular_buffer:: +data() const noexcept -> + const_buffers_type +{ + if(in_pos_ + in_len_ <= cap_) + return {{ + capy::const_buffer{ base_ + in_pos_, in_len_ }, + capy::const_buffer{ base_, 0} }}; + return {{ + capy::const_buffer{ base_ + in_pos_, cap_ - in_pos_}, + capy::const_buffer{ base_, in_len_- (cap_ - in_pos_)} }}; +} + +auto +circular_buffer:: +prepare(std::size_t n) -> + mutable_buffers_type +{ + // Buffer is too small for n + if(n > cap_ - in_len_) + detail::throw_length_error(); + + out_size_ = n; + auto const pos = ( + in_pos_ + in_len_) % cap_; + if(pos + n <= cap_) + return {{ + capy::mutable_buffer{ base_ + pos, n }, + capy::mutable_buffer{ base_, 0 } }}; + return {{ + capy::mutable_buffer{ base_ + pos, cap_ - pos }, + capy::mutable_buffer{ base_, n - (cap_ - pos) } }}; +} + +void +circular_buffer:: +commit( + std::size_t n) noexcept +{ + if(n < out_size_) + in_len_ += n; + else + in_len_ += out_size_; + out_size_ = 0; +} + +void +circular_buffer:: +consume( + std::size_t n) noexcept +{ + if(n < in_len_) + { + in_pos_ = (in_pos_ + n) % cap_; + in_len_ -= n; + } + else + { + // preserve in_pos_ if there is + // a prepared buffer + if(out_size_ != 0) + { + in_pos_ = (in_pos_ + in_len_) % cap_; + in_len_ = 0; + } + else + { + // make prepare return a + // bigger single buffer + in_pos_ = 0; + in_len_ = 0; + } + } +} + +} // detail +} // http +} // boost diff --git a/src/detail/filter.cpp b/src/detail/filter.cpp index 8023afd4..c5eb99f0 100644 --- a/src/detail/filter.cpp +++ b/src/detail/filter.cpp @@ -10,7 +10,7 @@ #include "src/detail/filter.hpp" -#include +#include #include namespace boost { @@ -42,8 +42,8 @@ process( std::array in_seq, bool more) -> results { - auto out = capy::buffer_slice(out_seq); - auto in = capy::buffer_slice(in_seq); + auto out = capy::consuming_buffers(out_seq); + auto in = capy::consuming_buffers(in_seq); results rv; bool p_more = true; @@ -78,8 +78,8 @@ process( return rv; } - out.remove_prefix(rs.out_bytes); - in.remove_prefix(rs.in_bytes); + out.consume(rs.out_bytes); + in.consume(rs.in_bytes); if(capy::buffer_size(out.data()) == 0) return rv; diff --git a/src/parser.cpp b/src/parser.cpp index a64d36c2..28b7dea7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -15,10 +15,11 @@ #include #include +#include +#include + #include -#include #include -#include #include #include #include @@ -461,9 +462,9 @@ class parser::impl std::size_t body_avail_; std::size_t nprepare_; - capy::flat_dynamic_buffer fb_; - capy::circular_dynamic_buffer cb0_; - capy::circular_dynamic_buffer cb1_; + detail::flat_buffer fb_; + detail::circular_buffer cb0_; + detail::circular_buffer cb1_; std::array mbp_; std::array cbp_; @@ -1153,7 +1154,7 @@ class parser::impl // in_place style auto copied = capy::buffer_copy( cb1_.prepare(cb1_.capacity()), - chunk.data()); + chunk); chunk_remain_ -= copied; body_avail_ += copied; body_total_ += copied; diff --git a/src/serializer.cpp b/src/serializer.cpp index 922c0bb9..39be7c0f 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -9,6 +9,7 @@ // Official repository: https://github.com/cppalliance/http // +#include #include #include #include @@ -19,7 +20,6 @@ #include "src/detail/buffer_utils.hpp" #include "src/detail/zlib_filter_base.hpp" -#include #include #include #include @@ -293,8 +293,8 @@ class serializer::impl std::unique_ptr filter_; - capy::circular_dynamic_buffer out_; - capy::circular_dynamic_buffer in_; + detail::circular_buffer out_; + detail::circular_buffer in_; detail::array_of_const_buffers prepped_; capy::const_buffer tmp_; diff --git a/test/unit/parser.cpp b/test/unit/parser.cpp index 50247afd..af7c3f74 100644 --- a/test/unit/parser.cpp +++ b/test/unit/parser.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/test/unit/serializer.cpp b/test/unit/serializer.cpp index cb33d84a..750ce4c5 100644 --- a/test/unit/serializer.cpp +++ b/test/unit/serializer.cpp @@ -13,14 +13,14 @@ #include #include -#include #include -#include +#include #include #include #include #include #include +#include #include "test_helpers.hpp" @@ -68,7 +68,7 @@ struct serializer_test // serializer::consume(), allowing tests to cover // state management within these functions std::string s; - for( auto buf : cbs.data()) + for( auto buf : cbs) { s.append( reinterpret_cast(buf.data()), @@ -172,8 +172,8 @@ struct serializer_test // serializer(serializer&&) { - std::string message; - capy::string_dynamic_buffer buf(&message); + char message[256]; + detail::flat_buffer buf(message, sizeof(message)); serializer sr1(cfg_); sr1.set_message(res); sr1.start(); @@ -200,7 +200,7 @@ struct serializer_test } BOOST_TEST(sr2.is_done()); - BOOST_TEST(message == expected); + BOOST_TEST(std::string_view(message, buf.size()) == expected); } }