1  
//
1  
//
2  
// Copyright (c) 2024 Christian Mazakas
2  
// Copyright (c) 2024 Christian Mazakas
3  
// Copyright (c) 2025 Mohammad Nejati
3  
// Copyright (c) 2025 Mohammad Nejati
4  
//
4  
//
5  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
6  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
//
7  
//
8  
// Official repository: https://github.com/cppalliance/http
8  
// Official repository: https://github.com/cppalliance/http
9  
//
9  
//
10  

10  

11  
#ifndef BOOST_HTTP_SRC_RFC_DETAIL_RULES_HPP
11  
#ifndef BOOST_HTTP_SRC_RFC_DETAIL_RULES_HPP
12  
#define BOOST_HTTP_SRC_RFC_DETAIL_RULES_HPP
12  
#define BOOST_HTTP_SRC_RFC_DETAIL_RULES_HPP
13  

13  

14  
#include <boost/http/detail/config.hpp>
14  
#include <boost/http/detail/config.hpp>
15  
#include <boost/http/rfc/detail/ws.hpp>
15  
#include <boost/http/rfc/detail/ws.hpp>
16  
#include <boost/http/rfc/token_rule.hpp>
16  
#include <boost/http/rfc/token_rule.hpp>
17  
#include <boost/http/status.hpp>
17  
#include <boost/http/status.hpp>
18  
#include <boost/core/detail/string_view.hpp>
18  
#include <boost/core/detail/string_view.hpp>
19  
#include <boost/system/result.hpp>
19  
#include <boost/system/result.hpp>
20  
#include <boost/url/grammar/delim_rule.hpp>
20  
#include <boost/url/grammar/delim_rule.hpp>
21  
#include <boost/url/grammar/error.hpp>
21  
#include <boost/url/grammar/error.hpp>
22  
#include <boost/url/grammar/lut_chars.hpp>
22  
#include <boost/url/grammar/lut_chars.hpp>
23  
#include <boost/url/grammar/token_rule.hpp>
23  
#include <boost/url/grammar/token_rule.hpp>
24  
#include <boost/url/grammar/tuple_rule.hpp>
24  
#include <boost/url/grammar/tuple_rule.hpp>
25  

25  

26  
namespace boost {
26  
namespace boost {
27  
namespace http {
27  
namespace http {
28  
namespace detail {
28  
namespace detail {
29  

29  

30  
//------------------------------------------------
30  
//------------------------------------------------
31  

31  

32  
/*  Used with list_rule
32  
/*  Used with list_rule
33  

33  

34  
    @par BNF
34  
    @par BNF
35  
    @code
35  
    @code
36  
    ows-comma   = OWS "," OWS
36  
    ows-comma   = OWS "," OWS
37  
    @endcode
37  
    @endcode
38  
*/
38  
*/
39  
struct ows_comma_ows_rule_t
39  
struct ows_comma_ows_rule_t
40  
{
40  
{
41  
    using value_type = void;
41  
    using value_type = void;
42  

42  

43  
    auto
43  
    auto
44  
    parse(
44  
    parse(
45  
        char const*& it,
45  
        char const*& it,
46  
        char const* end) const noexcept ->
46  
        char const* end) const noexcept ->
47  
            system::result<void>
47  
            system::result<void>
48  
    {
48  
    {
49  
        // OWS
49  
        // OWS
50  
        it = grammar::find_if_not(
50  
        it = grammar::find_if_not(
51  
            it, end, ws);
51  
            it, end, ws);
52  
        if(it == end)
52  
        if(it == end)
53  
            return grammar::error::mismatch;
53  
            return grammar::error::mismatch;
54  
        // ","
54  
        // ","
55  
        if(*it != ',')
55  
        if(*it != ',')
56  
            return grammar::error::mismatch;
56  
            return grammar::error::mismatch;
57  
        ++it;
57  
        ++it;
58  
        // OWS
58  
        // OWS
59  
        it = grammar::find_if_not(
59  
        it = grammar::find_if_not(
60  
            it, end, ws);
60  
            it, end, ws);
61  
        return {};
61  
        return {};
62  
    }
62  
    }
63  
};
63  
};
64  

64  

65  
constexpr ows_comma_ows_rule_t ows_comma_ows_rule{};
65  
constexpr ows_comma_ows_rule_t ows_comma_ows_rule{};
66  

66  

67  
//------------------------------------------------
67  
//------------------------------------------------
68  

68  

69  
// used for request-target
69  
// used for request-target
70  
//
70  
//
71  
// target-char    = <any OCTET except CTLs, and excluding LWS>
71  
// target-char    = <any OCTET except CTLs, and excluding LWS>
72  
//
72  
//
73  
struct target_chars_t
73  
struct target_chars_t
74  
{
74  
{
75  
    constexpr
75  
    constexpr
76  
    bool
76  
    bool
77  
    operator()(char c) const noexcept
77  
    operator()(char c) const noexcept
78  
    {
78  
    {
79  
        return
79  
        return
80  
            (static_cast<unsigned char>(c) >= 0x21) &&
80  
            (static_cast<unsigned char>(c) >= 0x21) &&
81  
            (static_cast<unsigned char>(c) <= 0x7e);
81  
            (static_cast<unsigned char>(c) <= 0x7e);
82  
    }
82  
    }
83  
};
83  
};
84  

84  

85  
constexpr target_chars_t target_chars{};
85  
constexpr target_chars_t target_chars{};
86  

86  

87  
//------------------------------------------------
87  
//------------------------------------------------
88  

88  

89  
// WS-VCHAR = SP / HTAB / VCHAR
89  
// WS-VCHAR = SP / HTAB / VCHAR
90  
struct ws_vchars_t
90  
struct ws_vchars_t
91  
{
91  
{
92  
    constexpr
92  
    constexpr
93  
    bool
93  
    bool
94  
    operator()(char ch) const noexcept
94  
    operator()(char ch) const noexcept
95  
    {
95  
    {
96  
        return (
96  
        return (
97  
            ch >= 0x20 && ch <= 0x7e) ||
97  
            ch >= 0x20 && ch <= 0x7e) ||
98  
            ch == 0x09;
98  
            ch == 0x09;
99  
    }
99  
    }
100  
};
100  
};
101  

101  

102  
constexpr ws_vchars_t ws_vchars{};
102  
constexpr ws_vchars_t ws_vchars{};
103  

103  

104  
//------------------------------------------------
104  
//------------------------------------------------
105  

105  

106  
// OWS         = *( SP / HTAB )
106  
// OWS         = *( SP / HTAB )
107  
inline
107  
inline
108  
void
108  
void
109  
skip_ows(
109  
skip_ows(
110  
    char const*& it,
110  
    char const*& it,
111  
    char const* end) noexcept
111  
    char const* end) noexcept
112  
{
112  
{
113  
    while(it != end)
113  
    while(it != end)
114  
    {
114  
    {
115  
        if(! ws(*it))
115  
        if(! ws(*it))
116  
            break;
116  
            break;
117  
        ++it;
117  
        ++it;
118  
    }
118  
    }
119  
}
119  
}
120  

120  

121  
struct ows_rule_t
121  
struct ows_rule_t
122  
{
122  
{
123  
    using value_type = void;
123  
    using value_type = void;
124  

124  

125  
    system::result<value_type>
125  
    system::result<value_type>
126  
    parse(
126  
    parse(
127  
        char const*& it,
127  
        char const*& it,
128  
        char const* end) noexcept
128  
        char const* end) noexcept
129  
    {
129  
    {
130  
        skip_ows(it, end);
130  
        skip_ows(it, end);
131  
        return system::error_code();
131  
        return system::error_code();
132  
    }
132  
    }
133  
};
133  
};
134  

134  

135  
constexpr ows_rule_t ows_rule{};
135  
constexpr ows_rule_t ows_rule{};
136  

136  

137  
//------------------------------------------------
137  
//------------------------------------------------
138  

138  

139  
// CRLF            = CR LF
139  
// CRLF            = CR LF
140  
struct crlf_rule_t
140  
struct crlf_rule_t
141  
{
141  
{
142  
    using value_type = void;
142  
    using value_type = void;
143  

143  

144  
    system::result<value_type>
144  
    system::result<value_type>
145  
    parse(
145  
    parse(
146  
        char const*& it,
146  
        char const*& it,
147  
        char const* end) const noexcept;
147  
        char const* end) const noexcept;
148  
};
148  
};
149  

149  

150  
constexpr crlf_rule_t crlf_rule{};
150  
constexpr crlf_rule_t crlf_rule{};
151  

151  

152  
//------------------------------------------------
152  
//------------------------------------------------
153  

153  

154  
// HTTP-version    = "HTTP/" DIGIT "." DIGIT
154  
// HTTP-version    = "HTTP/" DIGIT "." DIGIT
155  
struct version_rule_t
155  
struct version_rule_t
156  
{
156  
{
157  
    using value_type = unsigned char;
157  
    using value_type = unsigned char;
158  

158  

159  
    system::result<value_type>
159  
    system::result<value_type>
160  
    parse(
160  
    parse(
161  
        char const*& it,
161  
        char const*& it,
162  
        char const* end) const noexcept;
162  
        char const* end) const noexcept;
163  
};
163  
};
164  

164  

165  
constexpr version_rule_t version_rule{};
165  
constexpr version_rule_t version_rule{};
166  

166  

167  
//------------------------------------------------
167  
//------------------------------------------------
168  

168  

169  
// request-line    = method SP request-target SP HTTP-version CRLF
169  
// request-line    = method SP request-target SP HTTP-version CRLF
170  
constexpr auto
170  
constexpr auto
171  
request_line_rule =
171  
request_line_rule =
172  
    grammar::tuple_rule(
172  
    grammar::tuple_rule(
173  
        token_rule,
173  
        token_rule,
174  
        grammar::squelch(
174  
        grammar::squelch(
175  
            grammar::delim_rule(' ') ),
175  
            grammar::delim_rule(' ') ),
176  
        grammar::token_rule(
176  
        grammar::token_rule(
177  
            grammar::lut_chars(target_chars) ),
177  
            grammar::lut_chars(target_chars) ),
178  
        grammar::squelch(
178  
        grammar::squelch(
179  
            grammar::delim_rule(' ') ),
179  
            grammar::delim_rule(' ') ),
180  
        version_rule,
180  
        version_rule,
181  
        crlf_rule);
181  
        crlf_rule);
182  

182  

183  
//------------------------------------------------
183  
//------------------------------------------------
184  

184  

185  
// status-code     = 3DIGIT
185  
// status-code     = 3DIGIT
186  
struct status_code_rule_t
186  
struct status_code_rule_t
187  
{
187  
{
188  
    struct value_type
188  
    struct value_type
189  
    {
189  
    {
190  
        int v;
190  
        int v;
191  
        status st;
191  
        status st;
192  
        core::string_view s;
192  
        core::string_view s;
193  
    };
193  
    };
194  

194  

195  
    system::result<value_type>
195  
    system::result<value_type>
196  
    parse(
196  
    parse(
197  
        char const*& it,
197  
        char const*& it,
198  
        char const* end) const noexcept;
198  
        char const* end) const noexcept;
199  
};
199  
};
200  

200  

201  
constexpr status_code_rule_t status_code_rule{};
201  
constexpr status_code_rule_t status_code_rule{};
202  

202  

203  
//------------------------------------------------
203  
//------------------------------------------------
204  

204  

205  
// status-code     = *( HTAB / SP / VCHAR / obs-text )
205  
// status-code     = *( HTAB / SP / VCHAR / obs-text )
206  
struct reason_phrase_rule_t
206  
struct reason_phrase_rule_t
207  
{
207  
{
208  
    using value_type = core::string_view;
208  
    using value_type = core::string_view;
209  

209  

210  
    system::result<value_type>
210  
    system::result<value_type>
211  
    parse(
211  
    parse(
212  
        char const*& it,
212  
        char const*& it,
213  
        char const* end) const noexcept;
213  
        char const* end) const noexcept;
214  
};
214  
};
215  

215  

216  
constexpr reason_phrase_rule_t reason_phrase_rule{};
216  
constexpr reason_phrase_rule_t reason_phrase_rule{};
217  

217  

218  
//------------------------------------------------
218  
//------------------------------------------------
219  

219  

220  
// status-line     = HTTP-version SP status-code SP reason-phrase CRLF
220  
// status-line     = HTTP-version SP status-code SP reason-phrase CRLF
221  
constexpr auto
221  
constexpr auto
222  
status_line_rule =
222  
status_line_rule =
223  
    grammar::tuple_rule(
223  
    grammar::tuple_rule(
224  
        version_rule,
224  
        version_rule,
225  
        grammar::squelch(
225  
        grammar::squelch(
226  
            grammar::delim_rule(' ') ),
226  
            grammar::delim_rule(' ') ),
227  
        status_code_rule,
227  
        status_code_rule,
228  
        grammar::squelch(
228  
        grammar::squelch(
229  
            grammar::delim_rule(' ') ),
229  
            grammar::delim_rule(' ') ),
230  
        reason_phrase_rule,
230  
        reason_phrase_rule,
231  
        crlf_rule);
231  
        crlf_rule);
232  

232  

233  
//------------------------------------------------
233  
//------------------------------------------------
234  

234  

235  
struct field_rule_t
235  
struct field_rule_t
236  
{
236  
{
237  
    struct value_type
237  
    struct value_type
238  
    {
238  
    {
239  
        core::string_view name;
239  
        core::string_view name;
240  
        core::string_view value;
240  
        core::string_view value;
241  
        bool has_obs_fold = false;
241  
        bool has_obs_fold = false;
242  
    };
242  
    };
243  

243  

244  
    system::result<value_type>
244  
    system::result<value_type>
245  
    parse(
245  
    parse(
246  
        char const*& it,
246  
        char const*& it,
247  
        char const* end) const noexcept;
247  
        char const* end) const noexcept;
248  
};
248  
};
249  

249  

250  
constexpr field_rule_t field_rule{};
250  
constexpr field_rule_t field_rule{};
251  

251  

252  
/** Replace obs-fold with spaces
252  
/** Replace obs-fold with spaces
253  
*/
253  
*/
254  
void
254  
void
255  
remove_obs_fold(
255  
remove_obs_fold(
256  
    char *start,
256  
    char *start,
257  
    char const* end) noexcept;
257  
    char const* end) noexcept;
258  

258  

259  
// header-field   = field-name ":" OWS field-value OWS
259  
// header-field   = field-name ":" OWS field-value OWS
260  
struct field_name_rule_t
260  
struct field_name_rule_t
261  
{
261  
{
262  
    using value_type = core::string_view;
262  
    using value_type = core::string_view;
263  

263  

264  
    system::result<value_type>
264  
    system::result<value_type>
265  
    parse(
265  
    parse(
266  
        char const*& it,
266  
        char const*& it,
267  
        char const* end) const noexcept;
267  
        char const* end) const noexcept;
268  
};
268  
};
269  

269  

270  
constexpr field_name_rule_t field_name_rule{};
270  
constexpr field_name_rule_t field_name_rule{};
271  

271  

272  
struct field_value_rule_t
272  
struct field_value_rule_t
273  
{
273  
{
274  
    struct value_type
274  
    struct value_type
275  
    {
275  
    {
276  
        core::string_view value;
276  
        core::string_view value;
277  
        // detected occurrence of `\r\n `, `\r\n\t`
277  
        // detected occurrence of `\r\n `, `\r\n\t`
278  
        bool has_obs_fold = false;
278  
        bool has_obs_fold = false;
279  
        // detected `\r\nX`, attempt at field termination
279  
        // detected `\r\nX`, attempt at field termination
280  
        bool has_crlf = false;
280  
        bool has_crlf = false;
281  
    };
281  
    };
282  

282  

283  
    system::result<value_type>
283  
    system::result<value_type>
284  
    parse(
284  
    parse(
285  
        char const*& it,
285  
        char const*& it,
286  
        char const* end) const noexcept;
286  
        char const* end) const noexcept;
287  
};
287  
};
288  

288  

289  
constexpr field_value_rule_t field_value_rule{};
289  
constexpr field_value_rule_t field_value_rule{};
290  

290  

291  
} // detail
291  
} // detail
292  
} // http
292  
} // http
293  
} // boost
293  
} // boost
294  

294  

295  
#endif
295  
#endif