Line data Source code
1 : //
2 : // Copyright (c) 2024 Christian Mazakas
3 : // Copyright (c) 2025 Mohammad Nejati
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/http_proto
9 : //
10 :
11 : #ifndef BOOST_HTTP_PROTO_SRC_RFC_DETAIL_RULES_HPP
12 : #define BOOST_HTTP_PROTO_SRC_RFC_DETAIL_RULES_HPP
13 :
14 : #include <boost/http_proto/detail/config.hpp>
15 : #include <boost/http_proto/rfc/detail/ws.hpp>
16 : #include <boost/http_proto/rfc/token_rule.hpp>
17 : #include <boost/http_proto/status.hpp>
18 : #include <boost/core/detail/string_view.hpp>
19 : #include <boost/system/result.hpp>
20 : #include <boost/url/grammar/delim_rule.hpp>
21 : #include <boost/url/grammar/error.hpp>
22 : #include <boost/url/grammar/lut_chars.hpp>
23 : #include <boost/url/grammar/token_rule.hpp>
24 : #include <boost/url/grammar/tuple_rule.hpp>
25 :
26 : namespace boost {
27 : namespace http_proto {
28 : namespace detail {
29 :
30 : //------------------------------------------------
31 :
32 : /* Used with list_rule
33 :
34 : @par BNF
35 : @code
36 : ows-comma = OWS "," OWS
37 : @endcode
38 : */
39 : struct ows_comma_ows_rule_t
40 : {
41 : using value_type = void;
42 :
43 : auto
44 : parse(
45 : char const*& it,
46 : char const* end) const noexcept ->
47 : system::result<void>
48 : {
49 : // OWS
50 : it = grammar::find_if_not(
51 : it, end, ws);
52 : if(it == end)
53 : return grammar::error::mismatch;
54 : // ","
55 : if(*it != ',')
56 : return grammar::error::mismatch;
57 : ++it;
58 : // OWS
59 : it = grammar::find_if_not(
60 : it, end, ws);
61 : return {};
62 : }
63 : };
64 :
65 : constexpr ows_comma_ows_rule_t ows_comma_ows_rule{};
66 :
67 : //------------------------------------------------
68 :
69 : // used for request-target
70 : //
71 : // target-char = <any OCTET except CTLs, and excluding LWS>
72 : //
73 : struct target_chars_t
74 : {
75 : constexpr
76 : bool
77 : operator()(char c) const noexcept
78 : {
79 : return
80 : (static_cast<unsigned char>(c) >= 0x21) &&
81 : (static_cast<unsigned char>(c) <= 0x7e);
82 : }
83 : };
84 :
85 : constexpr target_chars_t target_chars{};
86 :
87 : //------------------------------------------------
88 :
89 : // WS-VCHAR = SP / HTAB / VCHAR
90 : struct ws_vchars_t
91 : {
92 : constexpr
93 : bool
94 2766 : operator()(char ch) const noexcept
95 : {
96 : return (
97 2766 : ch >= 0x20 && ch <= 0x7e) ||
98 2766 : ch == 0x09;
99 : }
100 : };
101 :
102 : constexpr ws_vchars_t ws_vchars{};
103 :
104 : //------------------------------------------------
105 :
106 : // OWS = *( SP / HTAB )
107 : inline
108 : void
109 : skip_ows(
110 : char const*& it,
111 : char const* end) noexcept
112 : {
113 : while(it != end)
114 : {
115 : if(! ws(*it))
116 : break;
117 : ++it;
118 : }
119 : }
120 :
121 : struct ows_rule_t
122 : {
123 : using value_type = void;
124 :
125 : system::result<value_type>
126 : parse(
127 : char const*& it,
128 : char const* end) noexcept
129 : {
130 : skip_ows(it, end);
131 : return system::error_code();
132 : }
133 : };
134 :
135 : constexpr ows_rule_t ows_rule{};
136 :
137 : //------------------------------------------------
138 :
139 : // CRLF = CR LF
140 : struct crlf_rule_t
141 : {
142 : using value_type = void;
143 :
144 : system::result<value_type>
145 : parse(
146 : char const*& it,
147 : char const* end) const noexcept;
148 : };
149 :
150 : constexpr crlf_rule_t crlf_rule{};
151 :
152 : //------------------------------------------------
153 :
154 : // HTTP-version = "HTTP/" DIGIT "." DIGIT
155 : struct version_rule_t
156 : {
157 : using value_type = unsigned char;
158 :
159 : system::result<value_type>
160 : parse(
161 : char const*& it,
162 : char const* end) const noexcept;
163 : };
164 :
165 : constexpr version_rule_t version_rule{};
166 :
167 : //------------------------------------------------
168 :
169 : // request-line = method SP request-target SP HTTP-version CRLF
170 : constexpr auto
171 : request_line_rule =
172 : grammar::tuple_rule(
173 : token_rule,
174 : grammar::squelch(
175 : grammar::delim_rule(' ') ),
176 : grammar::token_rule(
177 : grammar::lut_chars(target_chars) ),
178 : grammar::squelch(
179 : grammar::delim_rule(' ') ),
180 : version_rule,
181 : crlf_rule);
182 :
183 : //------------------------------------------------
184 :
185 : // status-code = 3DIGIT
186 : struct status_code_rule_t
187 : {
188 : struct value_type
189 : {
190 : int v;
191 : status st;
192 : core::string_view s;
193 : };
194 :
195 : system::result<value_type>
196 : parse(
197 : char const*& it,
198 : char const* end) const noexcept;
199 : };
200 :
201 : constexpr status_code_rule_t status_code_rule{};
202 :
203 : //------------------------------------------------
204 :
205 : // status-code = *( HTAB / SP / VCHAR / obs-text )
206 : struct reason_phrase_rule_t
207 : {
208 : using value_type = core::string_view;
209 :
210 : system::result<value_type>
211 : parse(
212 : char const*& it,
213 : char const* end) const noexcept;
214 : };
215 :
216 : constexpr reason_phrase_rule_t reason_phrase_rule{};
217 :
218 : //------------------------------------------------
219 :
220 : // status-line = HTTP-version SP status-code SP reason-phrase CRLF
221 : constexpr auto
222 : status_line_rule =
223 : grammar::tuple_rule(
224 : version_rule,
225 : grammar::squelch(
226 : grammar::delim_rule(' ') ),
227 : status_code_rule,
228 : grammar::squelch(
229 : grammar::delim_rule(' ') ),
230 : reason_phrase_rule,
231 : crlf_rule);
232 :
233 : //------------------------------------------------
234 :
235 : struct field_rule_t
236 : {
237 : struct value_type
238 : {
239 : core::string_view name;
240 : core::string_view value;
241 : bool has_obs_fold = false;
242 : };
243 :
244 : system::result<value_type>
245 : parse(
246 : char const*& it,
247 : char const* end) const noexcept;
248 : };
249 :
250 : constexpr field_rule_t field_rule{};
251 :
252 : /** Replace obs-fold with spaces
253 : */
254 : void
255 : remove_obs_fold(
256 : char *start,
257 : char const* end) noexcept;
258 :
259 : // header-field = field-name ":" OWS field-value OWS
260 : struct field_name_rule_t
261 : {
262 : using value_type = core::string_view;
263 :
264 : system::result<value_type>
265 : parse(
266 : char const*& it,
267 : char const* end) const noexcept;
268 : };
269 :
270 : constexpr field_name_rule_t field_name_rule{};
271 :
272 : struct field_value_rule_t
273 : {
274 : struct value_type
275 : {
276 : core::string_view value;
277 : // detected occurrence of `\r\n `, `\r\n\t`
278 : bool has_obs_fold = false;
279 : // detected `\r\nX`, attempt at field termination
280 : bool has_crlf = false;
281 : };
282 :
283 : system::result<value_type>
284 : parse(
285 : char const*& it,
286 : char const* end) const noexcept;
287 : };
288 :
289 : constexpr field_value_rule_t field_value_rule{};
290 :
291 : } // detail
292 : } // http_proto
293 : } // boost
294 :
295 : #endif
|