1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#include "src/rfc/detail/rules.hpp"
10  
#include "src/rfc/detail/rules.hpp"
11  

11  

12  
#include <boost/http/error.hpp>
12  
#include <boost/http/error.hpp>
13  
#include <boost/http/detail/config.hpp>
13  
#include <boost/http/detail/config.hpp>
14  
#include <boost/http/rfc/token_rule.hpp>
14  
#include <boost/http/rfc/token_rule.hpp>
15  

15  

16  
#include <boost/core/detail/string_view.hpp>
16  
#include <boost/core/detail/string_view.hpp>
17  
#include <boost/url/grammar/delim_rule.hpp>
17  
#include <boost/url/grammar/delim_rule.hpp>
18  
#include <boost/url/grammar/digit_chars.hpp>
18  
#include <boost/url/grammar/digit_chars.hpp>
19  
#include <boost/url/grammar/error.hpp>
19  
#include <boost/url/grammar/error.hpp>
20  
#include <boost/url/grammar/hexdig_chars.hpp>
20  
#include <boost/url/grammar/hexdig_chars.hpp>
21  
#include <boost/url/grammar/lut_chars.hpp>
21  
#include <boost/url/grammar/lut_chars.hpp>
22  
#include <boost/url/grammar/parse.hpp>
22  
#include <boost/url/grammar/parse.hpp>
23  
#include <boost/url/grammar/tuple_rule.hpp>
23  
#include <boost/url/grammar/tuple_rule.hpp>
24  

24  

25  
#include "src/rfc/detail/rules.hpp"
25  
#include "src/rfc/detail/rules.hpp"
26  

26  

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

30  

31  
auto
31  
auto
32  
crlf_rule_t::
32  
crlf_rule_t::
33  
parse(
33  
parse(
34  
    char const*& it,
34  
    char const*& it,
35  
    char const* end) const noexcept ->
35  
    char const* end) const noexcept ->
36  
        system::result<value_type>
36  
        system::result<value_type>
37  
{
37  
{
38  
    if(it == end)
38  
    if(it == end)
39  
        return grammar::error::need_more;
39  
        return grammar::error::need_more;
40  
    if(*it != '\r')
40  
    if(*it != '\r')
41  
        return grammar::error::mismatch;
41  
        return grammar::error::mismatch;
42  
    ++it;
42  
    ++it;
43  
    if(it == end)
43  
    if(it == end)
44  
        return grammar::error::need_more;
44  
        return grammar::error::need_more;
45  
    if(*it != '\n')
45  
    if(*it != '\n')
46  
        return grammar::error::mismatch;
46  
        return grammar::error::mismatch;
47  
    ++it;
47  
    ++it;
48  
    return {};
48  
    return {};
49  
}
49  
}
50  

50  

51  
//------------------------------------------------
51  
//------------------------------------------------
52  

52  

53  
auto
53  
auto
54  
version_rule_t::
54  
version_rule_t::
55  
parse(
55  
parse(
56  
    char const*& it,
56  
    char const*& it,
57  
    char const* end) const noexcept ->
57  
    char const* end) const noexcept ->
58  
        system::result<value_type>
58  
        system::result<value_type>
59  
{
59  
{
60  
    value_type v = 0;
60  
    value_type v = 0;
61  
    if(it == end)
61  
    if(it == end)
62  
    {
62  
    {
63  
        // expected "HTTP/"
63  
        // expected "HTTP/"
64  
        BOOST_HTTP_RETURN_EC(
64  
        BOOST_HTTP_RETURN_EC(
65  
            grammar::error::need_more);
65  
            grammar::error::need_more);
66  
    }
66  
    }
67  
    if(end - it >= 5)
67  
    if(end - it >= 5)
68  
    {
68  
    {
69  
        if(std::memcmp(
69  
        if(std::memcmp(
70  
            it, "HTTP/", 5) != 0)
70  
            it, "HTTP/", 5) != 0)
71  
        {
71  
        {
72  
            BOOST_HTTP_RETURN_EC(
72  
            BOOST_HTTP_RETURN_EC(
73  
                grammar::error::mismatch);
73  
                grammar::error::mismatch);
74  
        }
74  
        }
75  
        it += 5;
75  
        it += 5;
76  
    }
76  
    }
77  
    if(it == end)
77  
    if(it == end)
78  
    {
78  
    {
79  
        // expected DIGIT
79  
        // expected DIGIT
80  
        BOOST_HTTP_RETURN_EC(
80  
        BOOST_HTTP_RETURN_EC(
81  
            grammar::error::need_more);
81  
            grammar::error::need_more);
82  
    }
82  
    }
83  
    if(! grammar::digit_chars(*it))
83  
    if(! grammar::digit_chars(*it))
84  
    {
84  
    {
85  
        // expected DIGIT
85  
        // expected DIGIT
86  
        BOOST_HTTP_RETURN_EC(
86  
        BOOST_HTTP_RETURN_EC(
87  
            grammar::error::need_more);
87  
            grammar::error::need_more);
88  
    }
88  
    }
89  
    v = 10 * (*it++ - '0');
89  
    v = 10 * (*it++ - '0');
90  
    if(it == end)
90  
    if(it == end)
91  
    {
91  
    {
92  
        // expected "."
92  
        // expected "."
93  
        BOOST_HTTP_RETURN_EC(
93  
        BOOST_HTTP_RETURN_EC(
94  
            grammar::error::need_more);
94  
            grammar::error::need_more);
95  
    }
95  
    }
96  
    if(*it != '.')
96  
    if(*it != '.')
97  
    {
97  
    {
98  
        // expected "."
98  
        // expected "."
99  
        BOOST_HTTP_RETURN_EC(
99  
        BOOST_HTTP_RETURN_EC(
100  
            grammar::error::need_more);
100  
            grammar::error::need_more);
101  
    }
101  
    }
102  
    ++it;
102  
    ++it;
103  
    if(it == end)
103  
    if(it == end)
104  
    {
104  
    {
105  
        // expected DIGIT
105  
        // expected DIGIT
106  
        BOOST_HTTP_RETURN_EC(
106  
        BOOST_HTTP_RETURN_EC(
107  
            grammar::error::need_more);
107  
            grammar::error::need_more);
108  
    }
108  
    }
109  
    if(! grammar::digit_chars(*it))
109  
    if(! grammar::digit_chars(*it))
110  
    {
110  
    {
111  
        // expected DIGIT
111  
        // expected DIGIT
112  
        BOOST_HTTP_RETURN_EC(
112  
        BOOST_HTTP_RETURN_EC(
113  
            grammar::error::need_more);
113  
            grammar::error::need_more);
114  
    }
114  
    }
115  
    v += *it++ - '0';
115  
    v += *it++ - '0';
116  
    return v;
116  
    return v;
117  
}
117  
}
118  

118  

119  
//------------------------------------------------
119  
//------------------------------------------------
120  

120  

121  
auto
121  
auto
122  
status_code_rule_t::
122  
status_code_rule_t::
123  
parse(
123  
parse(
124  
    char const*& it,
124  
    char const*& it,
125  
    char const* end) const noexcept ->
125  
    char const* end) const noexcept ->
126  
        system::result<value_type>
126  
        system::result<value_type>
127  
{
127  
{
128  
    auto const dig =
128  
    auto const dig =
129  
        [](char c) -> int
129  
        [](char c) -> int
130  
        {
130  
        {
131  
            unsigned char uc(c - '0');
131  
            unsigned char uc(c - '0');
132  
            if(uc > 9)
132  
            if(uc > 9)
133  
                return -1;
133  
                return -1;
134  
            return uc;
134  
            return uc;
135  
        };
135  
        };
136  

136  

137  
    if(it == end)
137  
    if(it == end)
138  
    {
138  
    {
139  
        // end
139  
        // end
140  
        BOOST_HTTP_RETURN_EC(
140  
        BOOST_HTTP_RETURN_EC(
141  
            grammar::error::need_more);
141  
            grammar::error::need_more);
142  
    }
142  
    }
143  
    auto it0 = it;
143  
    auto it0 = it;
144  
    int v = dig(*it);
144  
    int v = dig(*it);
145  
    if(v == -1)
145  
    if(v == -1)
146  
    {
146  
    {
147  
        // expected DIGIT
147  
        // expected DIGIT
148  
        BOOST_HTTP_RETURN_EC(
148  
        BOOST_HTTP_RETURN_EC(
149  
            grammar::error::mismatch);
149  
            grammar::error::mismatch);
150  
    }
150  
    }
151  
    value_type t;
151  
    value_type t;
152  
    t.v = 100 * v;
152  
    t.v = 100 * v;
153  
    ++it;
153  
    ++it;
154  
    if(it == end)
154  
    if(it == end)
155  
    {
155  
    {
156  
        // end
156  
        // end
157  
        BOOST_HTTP_RETURN_EC(
157  
        BOOST_HTTP_RETURN_EC(
158  
            grammar::error::need_more);
158  
            grammar::error::need_more);
159  
    }
159  
    }
160  
    v = dig(*it);
160  
    v = dig(*it);
161  
    if(v == -1)
161  
    if(v == -1)
162  
    {
162  
    {
163  
        // expected DIGIT
163  
        // expected DIGIT
164  
        BOOST_HTTP_RETURN_EC(
164  
        BOOST_HTTP_RETURN_EC(
165  
            grammar::error::mismatch);
165  
            grammar::error::mismatch);
166  
    }
166  
    }
167  
    t.v = t.v + (10 * v);
167  
    t.v = t.v + (10 * v);
168  
    ++it;
168  
    ++it;
169  
    if(it == end)
169  
    if(it == end)
170  
    {
170  
    {
171  
        // end
171  
        // end
172  
        BOOST_HTTP_RETURN_EC(
172  
        BOOST_HTTP_RETURN_EC(
173  
            grammar::error::need_more);
173  
            grammar::error::need_more);
174  
    }
174  
    }
175  
    v = dig(*it);
175  
    v = dig(*it);
176  
    if(v == -1)
176  
    if(v == -1)
177  
    {
177  
    {
178  
        // expected DIGIT
178  
        // expected DIGIT
179  
        BOOST_HTTP_RETURN_EC(
179  
        BOOST_HTTP_RETURN_EC(
180  
            grammar::error::need_more);
180  
            grammar::error::need_more);
181  
    }
181  
    }
182  
    t.v = t.v + v;
182  
    t.v = t.v + v;
183  
    ++it;
183  
    ++it;
184  

184  

185  
    t.s = core::string_view(it0, it - it0);
185  
    t.s = core::string_view(it0, it - it0);
186  
    t.st = int_to_status(t.v);
186  
    t.st = int_to_status(t.v);
187  
    return t;
187  
    return t;
188  
}
188  
}
189  

189  

190  
//------------------------------------------------
190  
//------------------------------------------------
191  

191  

192  
auto
192  
auto
193  
reason_phrase_rule_t::
193  
reason_phrase_rule_t::
194  
parse(
194  
parse(
195  
    char const*& it,
195  
    char const*& it,
196  
    char const* end) const noexcept ->
196  
    char const* end) const noexcept ->
197  
        system::result<value_type>
197  
        system::result<value_type>
198  
{
198  
{
199  
    auto begin = it;
199  
    auto begin = it;
200  
    it = grammar::find_if_not(it, end, ws_vchars);
200  
    it = grammar::find_if_not(it, end, ws_vchars);
201  
    return core::string_view(begin, it);
201  
    return core::string_view(begin, it);
202  
}
202  
}
203  

203  

204  
//------------------------------------------------
204  
//------------------------------------------------
205  

205  

206  
auto
206  
auto
207  
field_name_rule_t::
207  
field_name_rule_t::
208  
parse(
208  
parse(
209  
    char const*& it,
209  
    char const*& it,
210  
    char const* end) const noexcept ->
210  
    char const* end) const noexcept ->
211  
        system::result<value_type>
211  
        system::result<value_type>
212  
{
212  
{
213  
    if( it == end )
213  
    if( it == end )
214  
        BOOST_HTTP_RETURN_EC(
214  
        BOOST_HTTP_RETURN_EC(
215  
            grammar::error::need_more);
215  
            grammar::error::need_more);
216  

216  

217  
    value_type v;
217  
    value_type v;
218  

218  

219  
    auto begin = it;
219  
    auto begin = it;
220  
    auto rv = grammar::parse(
220  
    auto rv = grammar::parse(
221  
        it, end, token_rule);
221  
        it, end, token_rule);
222  
    if( rv.has_error() || (it != end) )
222  
    if( rv.has_error() || (it != end) )
223  
    {
223  
    {
224  
        if( it != begin )
224  
        if( it != begin )
225  
        {
225  
        {
226  
            v = core::string_view(begin, it - begin);
226  
            v = core::string_view(begin, it - begin);
227  
            return v;
227  
            return v;
228  
        }
228  
        }
229  
        return error::bad_field_name;
229  
        return error::bad_field_name;
230  
    }
230  
    }
231  

231  

232  
    v = core::string_view(begin, end - begin);
232  
    v = core::string_view(begin, end - begin);
233  
    return v;
233  
    return v;
234  
}
234  
}
235  

235  

236  
auto
236  
auto
237  
field_value_rule_t::
237  
field_value_rule_t::
238  
parse(
238  
parse(
239  
    char const*& it,
239  
    char const*& it,
240  
    char const* end) const noexcept ->
240  
    char const* end) const noexcept ->
241  
        system::result<value_type>
241  
        system::result<value_type>
242  
{
242  
{
243  
    value_type v;
243  
    value_type v;
244  
    if( it == end )
244  
    if( it == end )
245  
    {
245  
    {
246  
        v.value = core::string_view(it, 0);
246  
        v.value = core::string_view(it, 0);
247  
        return v;
247  
        return v;
248  
    }
248  
    }
249  

249  

250  
    // field-line     = field-name ":" OWS field-value OWS
250  
    // field-line     = field-name ":" OWS field-value OWS
251  
    // field-value    = *field-content
251  
    // field-value    = *field-content
252  
    // field-content  = field-vchar
252  
    // field-content  = field-vchar
253  
    //                  [ 1*( SP / HTAB / field-vchar ) field-vchar ]
253  
    //                  [ 1*( SP / HTAB / field-vchar ) field-vchar ]
254  
    // field-vchar    = VCHAR / obs-text
254  
    // field-vchar    = VCHAR / obs-text
255  
    // obs-text       = %x80-FF
255  
    // obs-text       = %x80-FF
256  
    // VCHAR          = %x21-7E
256  
    // VCHAR          = %x21-7E
257  
    //                       ; visible (printing) characters
257  
    //                       ; visible (printing) characters
258  

258  

259  
    auto is_field_vchar = [](unsigned char ch)
259  
    auto is_field_vchar = [](unsigned char ch)
260  
    {
260  
    {
261  
      return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
261  
      return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262  
    };
262  
    };
263  

263  

264  
    char const* s0 = nullptr;
264  
    char const* s0 = nullptr;
265  
    char const* s1 = nullptr;
265  
    char const* s1 = nullptr;
266  

266  

267  
    bool has_crlf = false;
267  
    bool has_crlf = false;
268  
    bool has_obs_fold = false;
268  
    bool has_obs_fold = false;
269  

269  

270  
    while( it < end )
270  
    while( it < end )
271  
    {
271  
    {
272  
        auto ch = *it;
272  
        auto ch = *it;
273  
        if( ws(ch) )
273  
        if( ws(ch) )
274  
        {
274  
        {
275  
            ++it;
275  
            ++it;
276  
            continue;
276  
            continue;
277  
        }
277  
        }
278  

278  

279  
        if( ch == '\r' )
279  
        if( ch == '\r' )
280  
        {
280  
        {
281  
            // too short to know if we have a potential obs-fold
281  
            // too short to know if we have a potential obs-fold
282  
            // occurrence
282  
            // occurrence
283  
            if( end - it < 2 )
283  
            if( end - it < 2 )
284  
                BOOST_HTTP_RETURN_EC(
284  
                BOOST_HTTP_RETURN_EC(
285  
                    grammar::error::need_more);
285  
                    grammar::error::need_more);
286  

286  

287  
            if( it[1] != '\n' )
287  
            if( it[1] != '\n' )
288  
                goto done;
288  
                goto done;
289  

289  

290  
            if( end - it < 3 )
290  
            if( end - it < 3 )
291  
                BOOST_HTTP_RETURN_EC(
291  
                BOOST_HTTP_RETURN_EC(
292  
                    grammar::error::need_more);
292  
                    grammar::error::need_more);
293  

293  

294  
            if(! ws(it[2]) )
294  
            if(! ws(it[2]) )
295  
            {
295  
            {
296  
                has_crlf = true;
296  
                has_crlf = true;
297  
                goto done;
297  
                goto done;
298  
            }
298  
            }
299  

299  

300  
            has_obs_fold = true;
300  
            has_obs_fold = true;
301  
            it = it + 3;
301  
            it = it + 3;
302  
            continue;
302  
            continue;
303  
        }
303  
        }
304  

304  

305  
        if(! is_field_vchar(ch) )
305  
        if(! is_field_vchar(ch) )
306  
        {
306  
        {
307  
            goto done;
307  
            goto done;
308  
        }
308  
        }
309  

309  

310  
        if(! s0 )
310  
        if(! s0 )
311  
            s0 = it;
311  
            s0 = it;
312  

312  

313  
        ++it;
313  
        ++it;
314  
        s1 = it;
314  
        s1 = it;
315  
    }
315  
    }
316  

316  

317  
done:
317  
done:
318  
    // later routines wind up doing pointer
318  
    // later routines wind up doing pointer
319  
    // subtraction using the .data() member
319  
    // subtraction using the .data() member
320  
    // of the value so we need a valid 0-len range
320  
    // of the value so we need a valid 0-len range
321  
    if(! s0 )
321  
    if(! s0 )
322  
    {
322  
    {
323  
        s0 = it;
323  
        s0 = it;
324  
        s1 = s0;
324  
        s1 = s0;
325  
    }
325  
    }
326  

326  

327  
    v.value = core::string_view(s0, s1 - s0);
327  
    v.value = core::string_view(s0, s1 - s0);
328  
    v.has_crlf = has_crlf;
328  
    v.has_crlf = has_crlf;
329  
    v.has_obs_fold = has_obs_fold;
329  
    v.has_obs_fold = has_obs_fold;
330  
    return v;
330  
    return v;
331  
}
331  
}
332  

332  

333  
auto
333  
auto
334  
field_rule_t::
334  
field_rule_t::
335  
parse(
335  
parse(
336  
    char const*& it,
336  
    char const*& it,
337  
    char const* end) const noexcept ->
337  
    char const* end) const noexcept ->
338  
        system::result<value_type>
338  
        system::result<value_type>
339  
{
339  
{
340  
    if(it == end)
340  
    if(it == end)
341  
    {
341  
    {
342  
        BOOST_HTTP_RETURN_EC(
342  
        BOOST_HTTP_RETURN_EC(
343  
            grammar::error::need_more);
343  
            grammar::error::need_more);
344  
    }
344  
    }
345  
    // check for leading CRLF
345  
    // check for leading CRLF
346  
    if(it[0] == '\r')
346  
    if(it[0] == '\r')
347  
    {
347  
    {
348  
        ++it;
348  
        ++it;
349  
        if(it == end)
349  
        if(it == end)
350  
        {
350  
        {
351  
            BOOST_HTTP_RETURN_EC(
351  
            BOOST_HTTP_RETURN_EC(
352  
                grammar::error::need_more);
352  
                grammar::error::need_more);
353  
        }
353  
        }
354  
        if(*it != '\n')
354  
        if(*it != '\n')
355  
        {
355  
        {
356  
            BOOST_HTTP_RETURN_EC(
356  
            BOOST_HTTP_RETURN_EC(
357  
                grammar::error::mismatch);
357  
                grammar::error::mismatch);
358  
        }
358  
        }
359  
        // end of fields
359  
        // end of fields
360  
        ++it;
360  
        ++it;
361  
        BOOST_HTTP_RETURN_EC(
361  
        BOOST_HTTP_RETURN_EC(
362  
            grammar::error::end_of_range);
362  
            grammar::error::end_of_range);
363  
    }
363  
    }
364  

364  

365  
    value_type v;
365  
    value_type v;
366  
    auto rv = grammar::parse(
366  
    auto rv = grammar::parse(
367  
        it, end, grammar::tuple_rule(
367  
        it, end, grammar::tuple_rule(
368  
            field_name_rule,
368  
            field_name_rule,
369  
            grammar::delim_rule(':'),
369  
            grammar::delim_rule(':'),
370  
            field_value_rule,
370  
            field_value_rule,
371  
            crlf_rule));
371  
            crlf_rule));
372  

372  

373  
    if( rv.has_error() )
373  
    if( rv.has_error() )
374  
        return rv.error();
374  
        return rv.error();
375  

375  

376  
    auto val = rv.value();
376  
    auto val = rv.value();
377  
    v.name = std::get<0>(val);
377  
    v.name = std::get<0>(val);
378  
    v.value = std::get<2>(val).value;
378  
    v.value = std::get<2>(val).value;
379  
    v.has_obs_fold = std::get<2>(val).has_obs_fold;
379  
    v.has_obs_fold = std::get<2>(val).has_obs_fold;
380  

380  

381  
    return v;
381  
    return v;
382  
}
382  
}
383  

383  

384  
//------------------------------------------------
384  
//------------------------------------------------
385  

385  

386  
void
386  
void
387  
remove_obs_fold(
387  
remove_obs_fold(
388  
    char* it,
388  
    char* it,
389  
    char const* const end) noexcept
389  
    char const* const end) noexcept
390  
{
390  
{
391  
    while(it != end)
391  
    while(it != end)
392  
    {
392  
    {
393  
        if(*it != '\r')
393  
        if(*it != '\r')
394  
        {
394  
        {
395  
            ++it;
395  
            ++it;
396  
            continue;
396  
            continue;
397  
        }
397  
        }
398  
        if(end - it < 3)
398  
        if(end - it < 3)
399  
            break;
399  
            break;
400  
        BOOST_ASSERT(it[1] == '\n');
400  
        BOOST_ASSERT(it[1] == '\n');
401  
        if( it[1] == '\n' &&
401  
        if( it[1] == '\n' &&
402  
            ws(it[2]))
402  
            ws(it[2]))
403  
        {
403  
        {
404  
            it[0] = ' ';
404  
            it[0] = ' ';
405  
            it[1] = ' ';
405  
            it[1] = ' ';
406  
            it += 3;
406  
            it += 3;
407  
        }
407  
        }
408  
        else
408  
        else
409  
        {
409  
        {
410  
            ++it;
410  
            ++it;
411  
        }
411  
        }
412  
    }
412  
    }
413  
}
413  
}
414  

414  

415  
} // detail
415  
} // detail
416  
} // http
416  
} // http
417  
} // boost
417  
} // boost