1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2024 Mohammad Nejati
3  
// Copyright (c) 2024 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  
#include "src/rfc/detail/rules.hpp"
11  
#include "src/rfc/detail/rules.hpp"
12  
#include "src/rfc/detail/transfer_coding_rule.hpp"
12  
#include "src/rfc/detail/transfer_coding_rule.hpp"
13  

13  

14  
#include <boost/http/detail/header.hpp>
14  
#include <boost/http/detail/header.hpp>
15  
#include <boost/http/field.hpp>
15  
#include <boost/http/field.hpp>
16  
#include <boost/http/header_limits.hpp>
16  
#include <boost/http/header_limits.hpp>
17  
#include <boost/http/rfc/list_rule.hpp>
17  
#include <boost/http/rfc/list_rule.hpp>
18  
#include <boost/http/rfc/token_rule.hpp>
18  
#include <boost/http/rfc/token_rule.hpp>
19  
#include <boost/http/rfc/upgrade_rule.hpp>
19  
#include <boost/http/rfc/upgrade_rule.hpp>
20  
#include <boost/assert.hpp>
20  
#include <boost/assert.hpp>
21  
#include <boost/assert/source_location.hpp>
21  
#include <boost/assert/source_location.hpp>
22  
#include <boost/static_assert.hpp>
22  
#include <boost/static_assert.hpp>
23  
#include <boost/url/grammar/ci_string.hpp>
23  
#include <boost/url/grammar/ci_string.hpp>
24  
#include <boost/url/grammar/parse.hpp>
24  
#include <boost/url/grammar/parse.hpp>
25  
#include <boost/url/grammar/range_rule.hpp>
25  
#include <boost/url/grammar/range_rule.hpp>
26  
#include <boost/url/grammar/recycled.hpp>
26  
#include <boost/url/grammar/recycled.hpp>
27  
#include <boost/url/grammar/unsigned_rule.hpp>
27  
#include <boost/url/grammar/unsigned_rule.hpp>
28  

28  

29  
#include <utility>
29  
#include <utility>
30  

30  

31  
namespace boost {
31  
namespace boost {
32  
namespace http {
32  
namespace http {
33  
namespace detail {
33  
namespace detail {
34  

34  

35  
//------------------------------------------------
35  
//------------------------------------------------
36  

36  

37  
auto
37  
auto
38  
header::
38  
header::
39  
entry::
39  
entry::
40  
operator+(
40  
operator+(
41  
    std::size_t dv) const noexcept ->
41  
    std::size_t dv) const noexcept ->
42  
        entry
42  
        entry
43  
{
43  
{
44  
    return {
44  
    return {
45  
        static_cast<
45  
        static_cast<
46  
            offset_type>(np + dv),
46  
            offset_type>(np + dv),
47  
        nn,
47  
        nn,
48  
        static_cast<
48  
        static_cast<
49  
            offset_type>(vp + dv),
49  
            offset_type>(vp + dv),
50  
        vn,
50  
        vn,
51  
        id };
51  
        id };
52  
}
52  
}
53  

53  

54  
auto
54  
auto
55  
header::
55  
header::
56  
entry::
56  
entry::
57  
operator-(
57  
operator-(
58  
    std::size_t dv) const noexcept ->
58  
    std::size_t dv) const noexcept ->
59  
        entry
59  
        entry
60  
{
60  
{
61  
    return {
61  
    return {
62  
        static_cast<
62  
        static_cast<
63  
            offset_type>(np - dv),
63  
            offset_type>(np - dv),
64  
        nn,
64  
        nn,
65  
        static_cast<
65  
        static_cast<
66  
            offset_type>(vp - dv),
66  
            offset_type>(vp - dv),
67  
        vn,
67  
        vn,
68  
        id };
68  
        id };
69  
}
69  
}
70  

70  

71  
//------------------------------------------------
71  
//------------------------------------------------
72  

72  

73  
constexpr field header::unknown_field;
73  
constexpr field header::unknown_field;
74  

74  

75  
//------------------------------------------------
75  
//------------------------------------------------
76  

76  

77  
constexpr
77  
constexpr
78  
header::
78  
header::
79  
header(fields_tag) noexcept
79  
header(fields_tag) noexcept
80  
    : kind(detail::kind::fields)
80  
    : kind(detail::kind::fields)
81  
    , cbuf("\r\n")
81  
    , cbuf("\r\n")
82  
    , size(2)
82  
    , size(2)
83  
    , fld{}
83  
    , fld{}
84  
{
84  
{
85  
}
85  
}
86  

86  

87  
constexpr
87  
constexpr
88  
header::
88  
header::
89  
header(request_tag) noexcept
89  
header(request_tag) noexcept
90  
    : kind(detail::kind::request)
90  
    : kind(detail::kind::request)
91  
    , cbuf("GET / HTTP/1.1\r\n\r\n")
91  
    , cbuf("GET / HTTP/1.1\r\n\r\n")
92  
    , size(18)
92  
    , size(18)
93  
    , prefix(16)
93  
    , prefix(16)
94  
    , req{ 3, 1,
94  
    , req{ 3, 1,
95  
        http::method::get }
95  
        http::method::get }
96  
{
96  
{
97  
}
97  
}
98  

98  

99  
constexpr
99  
constexpr
100  
header::
100  
header::
101  
header(response_tag) noexcept
101  
header(response_tag) noexcept
102  
    : kind(detail::kind::response)
102  
    : kind(detail::kind::response)
103  
    , cbuf("HTTP/1.1 200 OK\r\n\r\n")
103  
    , cbuf("HTTP/1.1 200 OK\r\n\r\n")
104  
    , size(19)
104  
    , size(19)
105  
    , prefix(17)
105  
    , prefix(17)
106  
    , res{ 200,
106  
    , res{ 200,
107  
        http::status::ok }
107  
        http::status::ok }
108  
{
108  
{
109  
}
109  
}
110  

110  

111  
//------------------------------------------------
111  
//------------------------------------------------
112  

112  

113  
header const*
113  
header const*
114  
header::
114  
header::
115  
get_default(detail::kind k) noexcept
115  
get_default(detail::kind k) noexcept
116  
{
116  
{
117  
    static constexpr header h[3] = {
117  
    static constexpr header h[3] = {
118  
        fields_tag{},
118  
        fields_tag{},
119  
        request_tag{},
119  
        request_tag{},
120  
        response_tag{}};
120  
        response_tag{}};
121  
    return &h[k];
121  
    return &h[k];
122  
}
122  
}
123  

123  

124  
header::
124  
header::
125  
header(empty v) noexcept
125  
header(empty v) noexcept
126  
    : kind(v.param)
126  
    : kind(v.param)
127  
{
127  
{
128  
}
128  
}
129  

129  

130  
header::
130  
header::
131  
header(detail::kind k) noexcept
131  
header(detail::kind k) noexcept
132  
    : header(*get_default(k))
132  
    : header(*get_default(k))
133  
{
133  
{
134  
}
134  
}
135  

135  

136  
void
136  
void
137  
header::
137  
header::
138  
swap(header& h) noexcept
138  
swap(header& h) noexcept
139  
{
139  
{
140  
    std::swap(cbuf, h.cbuf);
140  
    std::swap(cbuf, h.cbuf);
141  
    std::swap(buf, h.buf);
141  
    std::swap(buf, h.buf);
142  
    std::swap(cap, h.cap);
142  
    std::swap(cap, h.cap);
143  
    std::swap(size, h.size);
143  
    std::swap(size, h.size);
144  
    std::swap(count, h.count);
144  
    std::swap(count, h.count);
145  
    std::swap(prefix, h.prefix);
145  
    std::swap(prefix, h.prefix);
146  
    std::swap(version, h.version);
146  
    std::swap(version, h.version);
147  
    std::swap(md, h.md);
147  
    std::swap(md, h.md);
148  
    switch(kind)
148  
    switch(kind)
149  
    {
149  
    {
150  
    default:
150  
    default:
151  
    case detail::kind::fields:
151  
    case detail::kind::fields:
152  
        break;
152  
        break;
153  
    case detail::kind::request:
153  
    case detail::kind::request:
154  
        std::swap(
154  
        std::swap(
155  
            req.method_len, h.req.method_len);
155  
            req.method_len, h.req.method_len);
156  
        std::swap(
156  
        std::swap(
157  
            req.target_len, h.req.target_len);
157  
            req.target_len, h.req.target_len);
158  
        std::swap(req.method, h.req.method);
158  
        std::swap(req.method, h.req.method);
159  
        break;
159  
        break;
160  
    case detail::kind::response:
160  
    case detail::kind::response:
161  
        std::swap(
161  
        std::swap(
162  
            res.status_int, h.res.status_int);
162  
            res.status_int, h.res.status_int);
163  
        std::swap(res.status, h.res.status);
163  
        std::swap(res.status, h.res.status);
164  
        break;
164  
        break;
165  
    }
165  
    }
166  
}
166  
}
167  

167  

168  
/*  References:
168  
/*  References:
169  

169  

170  
    6.3.  Persistence
170  
    6.3.  Persistence
171  
    https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
171  
    https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
172  
*/
172  
*/
173  
bool
173  
bool
174  
header::
174  
header::
175  
keep_alive() const noexcept
175  
keep_alive() const noexcept
176  
{
176  
{
177  
    if(md.payload == payload::error)
177  
    if(md.payload == payload::error)
178  
        return false;
178  
        return false;
179  
    if( version ==
179  
    if( version ==
180  
        http::version::http_1_1)
180  
        http::version::http_1_1)
181  
    {
181  
    {
182  
        if(md.connection.close)
182  
        if(md.connection.close)
183  
            return false;
183  
            return false;
184  
    }
184  
    }
185  
    else
185  
    else
186  
    {
186  
    {
187  
        if(! md.connection.keep_alive)
187  
        if(! md.connection.keep_alive)
188  
            return false;
188  
            return false;
189  
    }
189  
    }
190  
    // can't use to_eof in requests
190  
    // can't use to_eof in requests
191  
    BOOST_ASSERT(
191  
    BOOST_ASSERT(
192  
        kind != detail::kind::request ||
192  
        kind != detail::kind::request ||
193  
        md.payload != payload::to_eof);
193  
        md.payload != payload::to_eof);
194  
    if(md.payload == payload::to_eof)
194  
    if(md.payload == payload::to_eof)
195  
        return false;
195  
        return false;
196  
    return true;
196  
    return true;
197  
}
197  
}
198  

198  

199  
//------------------------------------------------
199  
//------------------------------------------------
200  

200  

201  
// return total bytes needed
201  
// return total bytes needed
202  
// to store message of `size`
202  
// to store message of `size`
203  
// bytes and `count` fields.
203  
// bytes and `count` fields.
204  
std::size_t
204  
std::size_t
205  
header::
205  
header::
206  
bytes_needed(
206  
bytes_needed(
207  
    std::size_t size,
207  
    std::size_t size,
208  
    std::size_t count) noexcept
208  
    std::size_t count) noexcept
209  
{
209  
{
210  
    // make sure `size` is big enough
210  
    // make sure `size` is big enough
211  
    // to hold the largest default buffer:
211  
    // to hold the largest default buffer:
212  
    // "HTTP/1.1 200 OK\r\n\r\n"
212  
    // "HTTP/1.1 200 OK\r\n\r\n"
213  
    if(size < 19)
213  
    if(size < 19)
214  
        size = 19;
214  
        size = 19;
215  

215  

216  
    // align size up to alignof(entry)
216  
    // align size up to alignof(entry)
217  
    size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1);
217  
    size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1);
218  

218  

219  
    return size + count * sizeof(entry);
219  
    return size + count * sizeof(entry);
220  
}
220  
}
221  

221  

222  
std::size_t
222  
std::size_t
223  
header::
223  
header::
224  
table_space(
224  
table_space(
225  
    std::size_t count) noexcept
225  
    std::size_t count) noexcept
226  
{
226  
{
227  
    return count *
227  
    return count *
228  
        sizeof(header::entry);
228  
        sizeof(header::entry);
229  
}
229  
}
230  

230  

231  
std::size_t
231  
std::size_t
232  
header::
232  
header::
233  
table_space() const noexcept
233  
table_space() const noexcept
234  
{
234  
{
235  
    return table_space(count);
235  
    return table_space(count);
236  
}
236  
}
237  

237  

238  
auto
238  
auto
239  
header::
239  
header::
240  
tab() const noexcept ->
240  
tab() const noexcept ->
241  
    table
241  
    table
242  
{
242  
{
243  
    BOOST_ASSERT(cap > 0);
243  
    BOOST_ASSERT(cap > 0);
244  
    BOOST_ASSERT(buf != nullptr);
244  
    BOOST_ASSERT(buf != nullptr);
245  
    return table(buf + cap);
245  
    return table(buf + cap);
246  
}
246  
}
247  

247  

248  
auto
248  
auto
249  
header::
249  
header::
250  
tab_() const noexcept ->
250  
tab_() const noexcept ->
251  
    entry*
251  
    entry*
252  
{
252  
{
253  
    return reinterpret_cast<
253  
    return reinterpret_cast<
254  
        entry*>(buf + cap);
254  
        entry*>(buf + cap);
255  
}
255  
}
256  

256  

257  
// return true if header cbuf is a default
257  
// return true if header cbuf is a default
258  
bool
258  
bool
259  
header::
259  
header::
260  
is_default() const noexcept
260  
is_default() const noexcept
261  
{
261  
{
262  
    return buf == nullptr;
262  
    return buf == nullptr;
263  
}
263  
}
264  

264  

265  
std::size_t
265  
std::size_t
266  
header::
266  
header::
267  
find(
267  
find(
268  
    field id) const noexcept
268  
    field id) const noexcept
269  
{
269  
{
270  
    if(count == 0)
270  
    if(count == 0)
271  
        return 0;
271  
        return 0;
272  
    std::size_t i = 0;
272  
    std::size_t i = 0;
273  
    auto const* p = &tab()[0];
273  
    auto const* p = &tab()[0];
274  
    while(i < count)
274  
    while(i < count)
275  
    {
275  
    {
276  
        if(p->id == id)
276  
        if(p->id == id)
277  
            break;
277  
            break;
278  
        ++i;
278  
        ++i;
279  
        --p;
279  
        --p;
280  
    }
280  
    }
281  
    return i;
281  
    return i;
282  
}
282  
}
283  

283  

284  
std::size_t
284  
std::size_t
285  
header::
285  
header::
286  
find(
286  
find(
287  
    core::string_view name) const noexcept
287  
    core::string_view name) const noexcept
288  
{
288  
{
289  
    if(count == 0)
289  
    if(count == 0)
290  
        return 0;
290  
        return 0;
291  
    std::size_t i = 0;
291  
    std::size_t i = 0;
292  
    auto const* p = &tab()[0];
292  
    auto const* p = &tab()[0];
293  
    while(i < count)
293  
    while(i < count)
294  
    {
294  
    {
295  
        core::string_view s(
295  
        core::string_view s(
296  
            cbuf + prefix + p->np,
296  
            cbuf + prefix + p->np,
297  
            p->nn);
297  
            p->nn);
298  
        if(grammar::ci_is_equal(s, name))
298  
        if(grammar::ci_is_equal(s, name))
299  
            break;
299  
            break;
300  
        ++i;
300  
        ++i;
301  
        --p;
301  
        --p;
302  
    }
302  
    }
303  
    return i;
303  
    return i;
304  
}
304  
}
305  

305  

306  
void
306  
void
307  
header::
307  
header::
308  
copy_table(
308  
copy_table(
309  
    void* dest,
309  
    void* dest,
310  
    std::size_t n) const noexcept
310  
    std::size_t n) const noexcept
311  
{
311  
{
312  
    // When `n == 0`, cbuf + cap may have incorrect
312  
    // When `n == 0`, cbuf + cap may have incorrect
313  
    // alignment, which can trigger UB sanitizer.
313  
    // alignment, which can trigger UB sanitizer.
314  
    if(n == 0)
314  
    if(n == 0)
315  
        return;
315  
        return;
316  

316  

317  
    std::memcpy(
317  
    std::memcpy(
318  
        reinterpret_cast<
318  
        reinterpret_cast<
319  
            entry*>(dest) - n,
319  
            entry*>(dest) - n,
320  
        reinterpret_cast<
320  
        reinterpret_cast<
321  
            entry const*>(
321  
            entry const*>(
322  
                cbuf + cap) - n,
322  
                cbuf + cap) - n,
323  
        n * sizeof(entry));
323  
        n * sizeof(entry));
324  
}
324  
}
325  

325  

326  
void
326  
void
327  
header::
327  
header::
328  
copy_table(
328  
copy_table(
329  
    void* dest) const noexcept
329  
    void* dest) const noexcept
330  
{
330  
{
331  
    copy_table(dest, count);
331  
    copy_table(dest, count);
332  
}
332  
}
333  

333  

334  
// assign all the members but
334  
// assign all the members but
335  
// preserve the allocated memory
335  
// preserve the allocated memory
336  
void
336  
void
337  
header::
337  
header::
338  
assign_to(
338  
assign_to(
339  
    header& dest) const noexcept
339  
    header& dest) const noexcept
340  
{
340  
{
341  
    auto const buf_ = dest.buf;
341  
    auto const buf_ = dest.buf;
342  
    auto const cbuf_ = dest.cbuf;
342  
    auto const cbuf_ = dest.cbuf;
343  
    auto const cap_ = dest.cap;
343  
    auto const cap_ = dest.cap;
344  
    dest = *this;
344  
    dest = *this;
345  
    dest.buf = buf_;
345  
    dest.buf = buf_;
346  
    dest.cbuf = cbuf_;
346  
    dest.cbuf = cbuf_;
347  
    dest.cap = cap_;
347  
    dest.cap = cap_;
348  
}
348  
}
349  

349  

350  
//------------------------------------------------
350  
//------------------------------------------------
351  
//
351  
//
352  
// Metadata
352  
// Metadata
353  
//
353  
//
354  
//------------------------------------------------
354  
//------------------------------------------------
355  

355  

356  
std::size_t
356  
std::size_t
357  
header::
357  
header::
358  
maybe_count(
358  
maybe_count(
359  
    field id) const noexcept
359  
    field id) const noexcept
360  
{
360  
{
361  
    if(kind == detail::kind::fields)
361  
    if(kind == detail::kind::fields)
362  
        return std::size_t(-1);
362  
        return std::size_t(-1);
363  
    switch(id)
363  
    switch(id)
364  
    {
364  
    {
365  
    case field::connection:
365  
    case field::connection:
366  
        return md.connection.count;
366  
        return md.connection.count;
367  
    case field::content_encoding:
367  
    case field::content_encoding:
368  
        return md.content_encoding.count;
368  
        return md.content_encoding.count;
369  
    case field::content_length:
369  
    case field::content_length:
370  
        return md.content_length.count;
370  
        return md.content_length.count;
371  
    case field::expect:
371  
    case field::expect:
372  
        return md.expect.count;
372  
        return md.expect.count;
373  
    case field::transfer_encoding:
373  
    case field::transfer_encoding:
374  
        return md.transfer_encoding.count;
374  
        return md.transfer_encoding.count;
375  
    case field::upgrade:
375  
    case field::upgrade:
376  
        return md.upgrade.count;
376  
        return md.upgrade.count;
377  
    default:
377  
    default:
378  
        break;
378  
        break;
379  
    }
379  
    }
380  
    return std::size_t(-1);
380  
    return std::size_t(-1);
381  
}
381  
}
382  

382  

383  
bool
383  
bool
384  
header::
384  
header::
385  
is_special(
385  
is_special(
386  
    field id) const noexcept
386  
    field id) const noexcept
387  
{
387  
{
388  
    if(kind == detail::kind::fields)
388  
    if(kind == detail::kind::fields)
389  
        return false;
389  
        return false;
390  
    switch(id)
390  
    switch(id)
391  
    {
391  
    {
392  
    case field::connection:
392  
    case field::connection:
393  
    case field::content_encoding:
393  
    case field::content_encoding:
394  
    case field::content_length:
394  
    case field::content_length:
395  
    case field::expect:
395  
    case field::expect:
396  
    case field::transfer_encoding:
396  
    case field::transfer_encoding:
397  
    case field::upgrade:
397  
    case field::upgrade:
398  
        return true;
398  
        return true;
399  
    default:
399  
    default:
400  
        break;
400  
        break;
401  
    }
401  
    }
402  
    return false;
402  
    return false;
403  
}
403  
}
404  

404  

405  
//------------------------------------------------
405  
//------------------------------------------------
406  

406  

407  
// called when the start-line changes
407  
// called when the start-line changes
408  
void
408  
void
409  
header::
409  
header::
410  
on_start_line()
410  
on_start_line()
411  
{
411  
{
412  
    // items in both the request-line
412  
    // items in both the request-line
413  
    // and the status-line can affect
413  
    // and the status-line can affect
414  
    // the payload, for example whether
414  
    // the payload, for example whether
415  
    // or not EOF marks the end of the
415  
    // or not EOF marks the end of the
416  
    // payload.
416  
    // payload.
417  

417  

418  
    update_payload();
418  
    update_payload();
419  
}
419  
}
420  

420  

421  
// called after a field is inserted
421  
// called after a field is inserted
422  
void
422  
void
423  
header::
423  
header::
424  
on_insert(
424  
on_insert(
425  
    field id,
425  
    field id,
426  
    core::string_view v)
426  
    core::string_view v)
427  
{
427  
{
428  
    if(kind == detail::kind::fields)
428  
    if(kind == detail::kind::fields)
429  
        return;
429  
        return;
430  
    switch(id)
430  
    switch(id)
431  
    {
431  
    {
432  
    case field::content_encoding:
432  
    case field::content_encoding:
433  
        return on_insert_content_encoding(v);
433  
        return on_insert_content_encoding(v);
434  
    case field::content_length:
434  
    case field::content_length:
435  
        return on_insert_content_length(v);
435  
        return on_insert_content_length(v);
436  
    case field::connection:
436  
    case field::connection:
437  
        return on_insert_connection(v);
437  
        return on_insert_connection(v);
438  
    case field::expect:
438  
    case field::expect:
439  
        return on_insert_expect(v);
439  
        return on_insert_expect(v);
440  
    case field::transfer_encoding:
440  
    case field::transfer_encoding:
441  
        return on_insert_transfer_encoding(v);
441  
        return on_insert_transfer_encoding(v);
442  
    case field::upgrade:
442  
    case field::upgrade:
443  
        return on_insert_upgrade(v);
443  
        return on_insert_upgrade(v);
444  
    default:
444  
    default:
445  
        break;
445  
        break;
446  
    }
446  
    }
447  
}
447  
}
448  

448  

449  
// called when one field is erased
449  
// called when one field is erased
450  
void
450  
void
451  
header::
451  
header::
452  
on_erase(field id)
452  
on_erase(field id)
453  
{
453  
{
454  
    if(kind == detail::kind::fields)
454  
    if(kind == detail::kind::fields)
455  
        return;
455  
        return;
456  
    switch(id)
456  
    switch(id)
457  
    {
457  
    {
458  
    case field::connection:
458  
    case field::connection:
459  
        return on_erase_connection();
459  
        return on_erase_connection();
460  
    case field::content_encoding:
460  
    case field::content_encoding:
461  
        return on_erase_content_encoding();
461  
        return on_erase_content_encoding();
462  
    case field::content_length:
462  
    case field::content_length:
463  
        return on_erase_content_length();
463  
        return on_erase_content_length();
464  
    case field::expect:
464  
    case field::expect:
465  
        return on_erase_expect();
465  
        return on_erase_expect();
466  
    case field::transfer_encoding:
466  
    case field::transfer_encoding:
467  
        return on_erase_transfer_encoding();
467  
        return on_erase_transfer_encoding();
468  
    case field::upgrade:
468  
    case field::upgrade:
469  
        return on_erase_upgrade();
469  
        return on_erase_upgrade();
470  
    default:
470  
    default:
471  
        break;
471  
        break;
472  
    }
472  
    }
473  
}
473  
}
474  

474  

475  
//------------------------------------------------
475  
//------------------------------------------------
476  

476  

477  
/*
477  
/*
478  
    https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
478  
    https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
479  
*/
479  
*/
480  
void
480  
void
481  
header::
481  
header::
482  
on_insert_connection(
482  
on_insert_connection(
483  
    core::string_view v)
483  
    core::string_view v)
484  
{
484  
{
485  
    ++md.connection.count;
485  
    ++md.connection.count;
486  
    if(md.connection.ec)
486  
    if(md.connection.ec)
487  
        return;
487  
        return;
488  
    auto rv = grammar::parse(
488  
    auto rv = grammar::parse(
489  
        v, list_rule(token_rule, 1));
489  
        v, list_rule(token_rule, 1));
490  
    if(! rv)
490  
    if(! rv)
491  
    {
491  
    {
492  
        md.connection.ec =
492  
        md.connection.ec =
493  
            BOOST_HTTP_ERR(
493  
            BOOST_HTTP_ERR(
494  
                error::bad_connection);
494  
                error::bad_connection);
495  
        return;
495  
        return;
496  
    }
496  
    }
497  
    md.connection.ec = {};
497  
    md.connection.ec = {};
498  
    for(auto t : *rv)
498  
    for(auto t : *rv)
499  
    {
499  
    {
500  
        if(grammar::ci_is_equal(
500  
        if(grammar::ci_is_equal(
501  
                t, "close"))
501  
                t, "close"))
502  
            md.connection.close = true;
502  
            md.connection.close = true;
503  
        else if(grammar::ci_is_equal(
503  
        else if(grammar::ci_is_equal(
504  
                t, "keep-alive"))
504  
                t, "keep-alive"))
505  
            md.connection.keep_alive = true;
505  
            md.connection.keep_alive = true;
506  
        else if(grammar::ci_is_equal(
506  
        else if(grammar::ci_is_equal(
507  
                t, "upgrade"))
507  
                t, "upgrade"))
508  
            md.connection.upgrade = true;
508  
            md.connection.upgrade = true;
509  
    }
509  
    }
510  
}
510  
}
511  

511  

512  
void
512  
void
513  
header::
513  
header::
514  
on_insert_content_length(
514  
on_insert_content_length(
515  
    core::string_view v)
515  
    core::string_view v)
516  
{
516  
{
517  
    static
517  
    static
518  
    constexpr
518  
    constexpr
519  
    grammar::unsigned_rule<
519  
    grammar::unsigned_rule<
520  
        std::uint64_t> num_rule{};
520  
        std::uint64_t> num_rule{};
521  

521  

522  
    ++md.content_length.count;
522  
    ++md.content_length.count;
523  
    if(md.content_length.ec)
523  
    if(md.content_length.ec)
524  
        return;
524  
        return;
525  
    auto rv =
525  
    auto rv =
526  
        grammar::parse(v, num_rule);
526  
        grammar::parse(v, num_rule);
527  
    if(! rv)
527  
    if(! rv)
528  
    {
528  
    {
529  
        // parse failure
529  
        // parse failure
530  
        md.content_length.ec =
530  
        md.content_length.ec =
531  
            BOOST_HTTP_ERR(
531  
            BOOST_HTTP_ERR(
532  
            error::bad_content_length);
532  
            error::bad_content_length);
533  
        md.content_length.value = 0;
533  
        md.content_length.value = 0;
534  
        update_payload();
534  
        update_payload();
535  
        return;
535  
        return;
536  
    }
536  
    }
537  
    if(md.content_length.count == 1)
537  
    if(md.content_length.count == 1)
538  
    {
538  
    {
539  
        // one value
539  
        // one value
540  
        md.content_length.ec = {};
540  
        md.content_length.ec = {};
541  
        md.content_length.value = *rv;
541  
        md.content_length.value = *rv;
542  
        update_payload();
542  
        update_payload();
543  
        return;
543  
        return;
544  
    }
544  
    }
545  
    if(*rv == md.content_length.value)
545  
    if(*rv == md.content_length.value)
546  
    {
546  
    {
547  
        // ok: duplicate value
547  
        // ok: duplicate value
548  
        return;
548  
        return;
549  
    }
549  
    }
550  
    // bad: different values
550  
    // bad: different values
551  
    md.content_length.ec =
551  
    md.content_length.ec =
552  
        BOOST_HTTP_ERR(
552  
        BOOST_HTTP_ERR(
553  
            error::multiple_content_length);
553  
            error::multiple_content_length);
554  
    md.content_length.value = 0;
554  
    md.content_length.value = 0;
555  
    update_payload();
555  
    update_payload();
556  
}
556  
}
557  

557  

558  
void
558  
void
559  
header::
559  
header::
560  
on_insert_expect(
560  
on_insert_expect(
561  
    core::string_view v)
561  
    core::string_view v)
562  
{
562  
{
563  
    ++md.expect.count;
563  
    ++md.expect.count;
564  
    if(kind != detail::kind::request)
564  
    if(kind != detail::kind::request)
565  
        return;
565  
        return;
566  
    if(md.expect.ec)
566  
    if(md.expect.ec)
567  
        return;
567  
        return;
568  
    // VFALCO Should we allow duplicate
568  
    // VFALCO Should we allow duplicate
569  
    // Expect fields that have 100-continue?
569  
    // Expect fields that have 100-continue?
570  
    if( md.expect.count > 1 ||
570  
    if( md.expect.count > 1 ||
571  
        ! grammar::ci_is_equal(v,
571  
        ! grammar::ci_is_equal(v,
572  
            "100-continue"))
572  
            "100-continue"))
573  
    {
573  
    {
574  
        md.expect.ec =
574  
        md.expect.ec =
575  
            BOOST_HTTP_ERR(
575  
            BOOST_HTTP_ERR(
576  
                error::bad_expect);
576  
                error::bad_expect);
577  
        md.expect.is_100_continue = false;
577  
        md.expect.is_100_continue = false;
578  
        return;
578  
        return;
579  
    }
579  
    }
580  
    md.expect.is_100_continue = true;
580  
    md.expect.is_100_continue = true;
581  
}
581  
}
582  

582  

583  
void
583  
void
584  
header::
584  
header::
585  
on_insert_transfer_encoding(
585  
on_insert_transfer_encoding(
586  
    core::string_view v)
586  
    core::string_view v)
587  
{
587  
{
588  
    ++md.transfer_encoding.count;
588  
    ++md.transfer_encoding.count;
589  
    if(md.transfer_encoding.ec)
589  
    if(md.transfer_encoding.ec)
590  
        return;
590  
        return;
591  

591  

592  
    auto rv = grammar::parse(
592  
    auto rv = grammar::parse(
593  
        v, list_rule(transfer_coding_rule, 1));
593  
        v, list_rule(transfer_coding_rule, 1));
594  
    if(! rv)
594  
    if(! rv)
595  
    {
595  
    {
596  
        // parse error
596  
        // parse error
597  
        goto error;
597  
        goto error;
598  
    }
598  
    }
599  
    for(auto t : *rv)
599  
    for(auto t : *rv)
600  
    {
600  
    {
601  
        if(! md.transfer_encoding.is_chunked)
601  
        if(! md.transfer_encoding.is_chunked)
602  
        {
602  
        {
603  
            if(t.id == transfer_coding_rule_t::chunked)
603  
            if(t.id == transfer_coding_rule_t::chunked)
604  
                md.transfer_encoding.is_chunked = true;
604  
                md.transfer_encoding.is_chunked = true;
605  
            continue;
605  
            continue;
606  
        }
606  
        }
607  
        if(t.id == transfer_coding_rule_t::chunked)
607  
        if(t.id == transfer_coding_rule_t::chunked)
608  
        {
608  
        {
609  
            // chunked appears twice
609  
            // chunked appears twice
610  
            goto error;
610  
            goto error;
611  
        }
611  
        }
612  
        // chunked must be last
612  
        // chunked must be last
613  
        goto error;
613  
        goto error;
614  
    }
614  
    }
615  
    update_payload();
615  
    update_payload();
616  
    return;
616  
    return;
617  

617  

618  
error:
618  
error:
619  
    md.transfer_encoding.ec =
619  
    md.transfer_encoding.ec =
620  
        BOOST_HTTP_ERR(
620  
        BOOST_HTTP_ERR(
621  
            error::bad_transfer_encoding);
621  
            error::bad_transfer_encoding);
622  
    md.transfer_encoding.is_chunked = false;
622  
    md.transfer_encoding.is_chunked = false;
623  
    update_payload();
623  
    update_payload();
624  
}
624  
}
625  

625  

626  
void
626  
void
627  
header::
627  
header::
628  
on_insert_content_encoding(
628  
on_insert_content_encoding(
629  
    core::string_view v)
629  
    core::string_view v)
630  
{
630  
{
631  
    ++md.content_encoding.count;
631  
    ++md.content_encoding.count;
632  
    if(md.content_encoding.ec)
632  
    if(md.content_encoding.ec)
633  
        return;
633  
        return;
634  

634  

635  
    auto rv = grammar::parse(
635  
    auto rv = grammar::parse(
636  
        v, list_rule(token_rule, 1));
636  
        v, list_rule(token_rule, 1));
637  
    if(!rv)
637  
    if(!rv)
638  
    {
638  
    {
639  
        md.content_encoding.ec =
639  
        md.content_encoding.ec =
640  
            BOOST_HTTP_ERR(
640  
            BOOST_HTTP_ERR(
641  
                error::bad_content_encoding);
641  
                error::bad_content_encoding);
642  
        md.content_encoding.coding =
642  
        md.content_encoding.coding =
643  
            content_coding::unknown;
643  
            content_coding::unknown;
644  
        return;
644  
        return;
645  
    }
645  
    }
646  

646  

647  
    if(rv->size() > 1 || md.content_encoding.count > 1)
647  
    if(rv->size() > 1 || md.content_encoding.count > 1)
648  
    {
648  
    {
649  
        md.content_encoding.coding =
649  
        md.content_encoding.coding =
650  
            content_coding::unknown;
650  
            content_coding::unknown;
651  
        return;
651  
        return;
652  
    }
652  
    }
653  

653  

654  
    if(grammar::ci_is_equal(
654  
    if(grammar::ci_is_equal(
655  
        *rv->begin(), "deflate"))
655  
        *rv->begin(), "deflate"))
656  
    {
656  
    {
657  
        md.content_encoding.coding =
657  
        md.content_encoding.coding =
658  
            content_coding::deflate;
658  
            content_coding::deflate;
659  
    }
659  
    }
660  
    else if(grammar::ci_is_equal(
660  
    else if(grammar::ci_is_equal(
661  
        *rv->begin(), "gzip"))
661  
        *rv->begin(), "gzip"))
662  
    {
662  
    {
663  
        md.content_encoding.coding =
663  
        md.content_encoding.coding =
664  
            content_coding::gzip;
664  
            content_coding::gzip;
665  
    }
665  
    }
666  
    else if(grammar::ci_is_equal(
666  
    else if(grammar::ci_is_equal(
667  
        *rv->begin(), "br"))
667  
        *rv->begin(), "br"))
668  
    {
668  
    {
669  
        md.content_encoding.coding =
669  
        md.content_encoding.coding =
670  
            content_coding::br;
670  
            content_coding::br;
671  
    }
671  
    }
672  
    else
672  
    else
673  
    {
673  
    {
674  
        md.content_encoding.coding =
674  
        md.content_encoding.coding =
675  
            content_coding::unknown;
675  
            content_coding::unknown;
676  
    }
676  
    }
677  
}
677  
}
678  

678  

679  
void
679  
void
680  
header::
680  
header::
681  
on_insert_upgrade(
681  
on_insert_upgrade(
682  
    core::string_view v)
682  
    core::string_view v)
683  
{
683  
{
684  
    ++md.upgrade.count;
684  
    ++md.upgrade.count;
685  
    if(md.upgrade.ec)
685  
    if(md.upgrade.ec)
686  
        return;
686  
        return;
687  
    if( version !=
687  
    if( version !=
688  
        http::version::http_1_1)
688  
        http::version::http_1_1)
689  
    {
689  
    {
690  
        md.upgrade.ec =
690  
        md.upgrade.ec =
691  
            BOOST_HTTP_ERR(
691  
            BOOST_HTTP_ERR(
692  
                error::bad_upgrade);
692  
                error::bad_upgrade);
693  
        md.upgrade.websocket = false;
693  
        md.upgrade.websocket = false;
694  
        return;
694  
        return;
695  
    }
695  
    }
696  
    auto rv = grammar::parse(
696  
    auto rv = grammar::parse(
697  
        v, upgrade_rule);
697  
        v, upgrade_rule);
698  
    if(! rv)
698  
    if(! rv)
699  
    {
699  
    {
700  
        md.upgrade.ec =
700  
        md.upgrade.ec =
701  
            BOOST_HTTP_ERR(
701  
            BOOST_HTTP_ERR(
702  
                error::bad_upgrade);
702  
                error::bad_upgrade);
703  
        md.upgrade.websocket = false;
703  
        md.upgrade.websocket = false;
704  
        return;
704  
        return;
705  
    }
705  
    }
706  
    if(! md.upgrade.websocket)
706  
    if(! md.upgrade.websocket)
707  
    {
707  
    {
708  
        for(auto t : *rv)
708  
        for(auto t : *rv)
709  
        {
709  
        {
710  
            if( grammar::ci_is_equal(
710  
            if( grammar::ci_is_equal(
711  
                    t.name, "websocket") &&
711  
                    t.name, "websocket") &&
712  
                t.version.empty())
712  
                t.version.empty())
713  
            {
713  
            {
714  
                md.upgrade.websocket = true;
714  
                md.upgrade.websocket = true;
715  
                break;
715  
                break;
716  
            }
716  
            }
717  
        }
717  
        }
718  
    }
718  
    }
719  
}
719  
}
720  

720  

721  
//------------------------------------------------
721  
//------------------------------------------------
722  

722  

723  
void
723  
void
724  
header::
724  
header::
725  
on_erase_connection()
725  
on_erase_connection()
726  
{
726  
{
727  
    BOOST_ASSERT(
727  
    BOOST_ASSERT(
728  
        md.connection.count > 0);
728  
        md.connection.count > 0);
729  
    // reset and re-insert
729  
    // reset and re-insert
730  
    auto n = md.connection.count - 1;
730  
    auto n = md.connection.count - 1;
731  
    auto const p = cbuf + prefix;
731  
    auto const p = cbuf + prefix;
732  
    auto const* e = &tab()[0];
732  
    auto const* e = &tab()[0];
733  
    md.connection = {};
733  
    md.connection = {};
734  
    while(n > 0)
734  
    while(n > 0)
735  
    {
735  
    {
736  
        if(e->id == field::connection)
736  
        if(e->id == field::connection)
737  
        {
737  
        {
738  
            on_insert_connection(
738  
            on_insert_connection(
739  
                core::string_view(
739  
                core::string_view(
740  
                    p + e->vp, e->vn));
740  
                    p + e->vp, e->vn));
741  
            --n;
741  
            --n;
742  
        }
742  
        }
743  
        --e;
743  
        --e;
744  
    }
744  
    }
745  
}
745  
}
746  

746  

747  
void
747  
void
748  
header::
748  
header::
749  
on_erase_content_length()
749  
on_erase_content_length()
750  
{
750  
{
751  
    BOOST_ASSERT(
751  
    BOOST_ASSERT(
752  
        md.content_length.count > 0);
752  
        md.content_length.count > 0);
753  
    --md.content_length.count;
753  
    --md.content_length.count;
754  
    if(md.content_length.count == 0)
754  
    if(md.content_length.count == 0)
755  
    {
755  
    {
756  
        // no Content-Length
756  
        // no Content-Length
757  
        md.content_length = {};
757  
        md.content_length = {};
758  
        update_payload();
758  
        update_payload();
759  
        return;
759  
        return;
760  
    }
760  
    }
761  
    if(! md.content_length.ec)
761  
    if(! md.content_length.ec)
762  
    {
762  
    {
763  
        // removing a duplicate value
763  
        // removing a duplicate value
764  
        return;
764  
        return;
765  
    }
765  
    }
766  
    // reset and re-insert
766  
    // reset and re-insert
767  
    auto n = md.content_length.count;
767  
    auto n = md.content_length.count;
768  
    auto const p = cbuf + prefix;
768  
    auto const p = cbuf + prefix;
769  
    auto const* e = &tab()[0];
769  
    auto const* e = &tab()[0];
770  
    md.content_length = {};
770  
    md.content_length = {};
771  
    while(n > 0)
771  
    while(n > 0)
772  
    {
772  
    {
773  
        if(e->id == field::content_length)
773  
        if(e->id == field::content_length)
774  
        {
774  
        {
775  
            on_insert_content_length(
775  
            on_insert_content_length(
776  
                core::string_view(
776  
                core::string_view(
777  
                    p + e->vp, e->vn));
777  
                    p + e->vp, e->vn));
778  
            --n;
778  
            --n;
779  
        }
779  
        }
780  
        --e;
780  
        --e;
781  
    }
781  
    }
782  
    update_payload();
782  
    update_payload();
783  
}
783  
}
784  

784  

785  
void
785  
void
786  
header::
786  
header::
787  
on_erase_expect()
787  
on_erase_expect()
788  
{
788  
{
789  
    BOOST_ASSERT(
789  
    BOOST_ASSERT(
790  
        md.expect.count > 0);
790  
        md.expect.count > 0);
791  
    --md.expect.count;
791  
    --md.expect.count;
792  
    if(kind != detail::kind::request)
792  
    if(kind != detail::kind::request)
793  
        return;
793  
        return;
794  
    if(md.expect.count == 0)
794  
    if(md.expect.count == 0)
795  
    {
795  
    {
796  
        // no Expect
796  
        // no Expect
797  
        md.expect = {};
797  
        md.expect = {};
798  
        return;
798  
        return;
799  
    }
799  
    }
800  
    // VFALCO This should be uncommented
800  
    // VFALCO This should be uncommented
801  
    // if we want to allow multiple Expect
801  
    // if we want to allow multiple Expect
802  
    // fields with the value 100-continue
802  
    // fields with the value 100-continue
803  
    /*
803  
    /*
804  
    if(! md.expect.ec)
804  
    if(! md.expect.ec)
805  
        return;
805  
        return;
806  
    */
806  
    */
807  
    // reset and re-insert
807  
    // reset and re-insert
808  
    auto n = md.expect.count;
808  
    auto n = md.expect.count;
809  
    auto const p = cbuf + prefix;
809  
    auto const p = cbuf + prefix;
810  
    auto const* e = &tab()[0];
810  
    auto const* e = &tab()[0];
811  
    md.expect = {};
811  
    md.expect = {};
812  
    while(n > 0)
812  
    while(n > 0)
813  
    {
813  
    {
814  
        if(e->id == field::expect)
814  
        if(e->id == field::expect)
815  
        {
815  
        {
816  
            on_insert_expect(
816  
            on_insert_expect(
817  
                core::string_view(
817  
                core::string_view(
818  
                    p + e->vp, e->vn));
818  
                    p + e->vp, e->vn));
819  
            --n;
819  
            --n;
820  
        }
820  
        }
821  
        --e;
821  
        --e;
822  
    }
822  
    }
823  
}
823  
}
824  

824  

825  
void
825  
void
826  
header::
826  
header::
827  
on_erase_transfer_encoding()
827  
on_erase_transfer_encoding()
828  
{
828  
{
829  
    BOOST_ASSERT(
829  
    BOOST_ASSERT(
830  
        md.transfer_encoding.count > 0);
830  
        md.transfer_encoding.count > 0);
831  
    // reset and re-insert
831  
    // reset and re-insert
832  
    auto n = md.transfer_encoding.count - 1;
832  
    auto n = md.transfer_encoding.count - 1;
833  
    auto const p = cbuf + prefix;
833  
    auto const p = cbuf + prefix;
834  
    auto const* e = &tab()[0];
834  
    auto const* e = &tab()[0];
835  
    md.transfer_encoding = {};
835  
    md.transfer_encoding = {};
836  
    while(n > 0)
836  
    while(n > 0)
837  
    {
837  
    {
838  
        if(e->id == field::transfer_encoding)
838  
        if(e->id == field::transfer_encoding)
839  
        {
839  
        {
840  
            on_insert_transfer_encoding(
840  
            on_insert_transfer_encoding(
841  
                core::string_view(
841  
                core::string_view(
842  
                    p + e->vp, e->vn));
842  
                    p + e->vp, e->vn));
843  
            --n;
843  
            --n;
844  
        }
844  
        }
845  
        --e;
845  
        --e;
846  
    }
846  
    }
847  
}
847  
}
848  

848  

849  
void
849  
void
850  
header::
850  
header::
851  
on_erase_content_encoding()
851  
on_erase_content_encoding()
852  
{
852  
{
853  
    BOOST_ASSERT(
853  
    BOOST_ASSERT(
854  
        md.content_encoding.count > 0);
854  
        md.content_encoding.count > 0);
855  
    --md.content_encoding.count;
855  
    --md.content_encoding.count;
856  
    if(md.content_encoding.count == 0)
856  
    if(md.content_encoding.count == 0)
857  
    {
857  
    {
858  
        // no Content-Encoding
858  
        // no Content-Encoding
859  
        md.content_encoding = {};
859  
        md.content_encoding = {};
860  
        return;
860  
        return;
861  
    }
861  
    }
862  
    // re-insert everything
862  
    // re-insert everything
863  
    --md.content_encoding.count;
863  
    --md.content_encoding.count;
864  
    // TODO
864  
    // TODO
865  
    // on_insert_content_encoding();
865  
    // on_insert_content_encoding();
866  
}
866  
}
867  

867  

868  
// called when Upgrade is erased
868  
// called when Upgrade is erased
869  
void
869  
void
870  
header::
870  
header::
871  
on_erase_upgrade()
871  
on_erase_upgrade()
872  
{
872  
{
873  
    BOOST_ASSERT(
873  
    BOOST_ASSERT(
874  
        md.upgrade.count > 0);
874  
        md.upgrade.count > 0);
875  
    --md.upgrade.count;
875  
    --md.upgrade.count;
876  
    if(md.upgrade.count == 0)
876  
    if(md.upgrade.count == 0)
877  
    {
877  
    {
878  
        // no Upgrade
878  
        // no Upgrade
879  
        md.upgrade = {};
879  
        md.upgrade = {};
880  
        return;
880  
        return;
881  
    }
881  
    }
882  
    // reset and re-insert
882  
    // reset and re-insert
883  
    auto n = md.upgrade.count;
883  
    auto n = md.upgrade.count;
884  
    auto const p = cbuf + prefix;
884  
    auto const p = cbuf + prefix;
885  
    auto const* e = &tab()[0];
885  
    auto const* e = &tab()[0];
886  
    md.upgrade = {};
886  
    md.upgrade = {};
887  
    while(n > 0)
887  
    while(n > 0)
888  
    {
888  
    {
889  
        if(e->id == field::upgrade)
889  
        if(e->id == field::upgrade)
890  
            on_insert_upgrade(
890  
            on_insert_upgrade(
891  
                core::string_view(
891  
                core::string_view(
892  
                    p + e->vp, e->vn));
892  
                    p + e->vp, e->vn));
893  
        --n;
893  
        --n;
894  
        --e;
894  
        --e;
895  
    }
895  
    }
896  
}
896  
}
897  

897  

898  
//------------------------------------------------
898  
//------------------------------------------------
899  

899  

900  
// called when all fields with id are removed
900  
// called when all fields with id are removed
901  
void
901  
void
902  
header::
902  
header::
903  
on_erase_all(
903  
on_erase_all(
904  
    field id)
904  
    field id)
905  
{
905  
{
906  
    if(kind == detail::kind::fields)
906  
    if(kind == detail::kind::fields)
907  
        return;
907  
        return;
908  
    switch(id)
908  
    switch(id)
909  
    {
909  
    {
910  
    case field::connection:
910  
    case field::connection:
911  
        md.connection = {};
911  
        md.connection = {};
912  
        return;
912  
        return;
913  

913  

914  
    case field::content_length:
914  
    case field::content_length:
915  
        md.content_length = {};
915  
        md.content_length = {};
916  
        update_payload();
916  
        update_payload();
917  
        return;
917  
        return;
918  

918  

919  
    case field::expect:
919  
    case field::expect:
920  
        md.expect = {};
920  
        md.expect = {};
921  
        update_payload();
921  
        update_payload();
922  
        return;
922  
        return;
923  

923  

924  
    case field::transfer_encoding:
924  
    case field::transfer_encoding:
925  
        md.transfer_encoding = {};
925  
        md.transfer_encoding = {};
926  
        update_payload();
926  
        update_payload();
927  
        return;
927  
        return;
928  

928  

929  
    case field::upgrade:
929  
    case field::upgrade:
930  
        md.upgrade = {};
930  
        md.upgrade = {};
931  
        return;
931  
        return;
932  

932  

933  
    default:
933  
    default:
934  
        break;
934  
        break;
935  
    }
935  
    }
936  
}
936  
}
937  

937  

938  
//------------------------------------------------
938  
//------------------------------------------------
939  

939  

940  
/*  References:
940  
/*  References:
941  

941  

942  
    3.3.  Message Body
942  
    3.3.  Message Body
943  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
943  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
944  

944  

945  
    3.3.1.  Transfer-Encoding
945  
    3.3.1.  Transfer-Encoding
946  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
946  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
947  

947  

948  
    3.3.2.  Content-Length
948  
    3.3.2.  Content-Length
949  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
949  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
950  
*/
950  
*/
951  
void
951  
void
952  
header::
952  
header::
953  
update_payload() noexcept
953  
update_payload() noexcept
954  
{
954  
{
955  
    BOOST_ASSERT(kind !=
955  
    BOOST_ASSERT(kind !=
956  
        detail::kind::fields);
956  
        detail::kind::fields);
957  
    if(md.payload_override)
957  
    if(md.payload_override)
958  
    {
958  
    {
959  
        // e.g. response to
959  
        // e.g. response to
960  
        // a HEAD request
960  
        // a HEAD request
961  
        return;
961  
        return;
962  
    }
962  
    }
963  

963  

964  
/*  If there is an error in either Content-Length
964  
/*  If there is an error in either Content-Length
965  
    or Transfer-Encoding, then the payload is
965  
    or Transfer-Encoding, then the payload is
966  
    undefined. Clients should probably close the
966  
    undefined. Clients should probably close the
967  
    connection. Servers can send a Bad Request
967  
    connection. Servers can send a Bad Request
968  
    and avoid reading any payload bytes.
968  
    and avoid reading any payload bytes.
969  
*/
969  
*/
970  
    if(md.content_length.ec)
970  
    if(md.content_length.ec)
971  
    {
971  
    {
972  
        // invalid Content-Length
972  
        // invalid Content-Length
973  
        md.payload = payload::error;
973  
        md.payload = payload::error;
974  
        md.payload_size = 0;
974  
        md.payload_size = 0;
975  
        return;
975  
        return;
976  
    }
976  
    }
977  
    if(md.transfer_encoding.ec)
977  
    if(md.transfer_encoding.ec)
978  
    {
978  
    {
979  
        // invalid Transfer-Encoding
979  
        // invalid Transfer-Encoding
980  
        md.payload = payload::error;
980  
        md.payload = payload::error;
981  
        md.payload_size = 0;
981  
        md.payload_size = 0;
982  
        return;
982  
        return;
983  
    }
983  
    }
984  

984  

985  
/*  A sender MUST NOT send a Content-Length
985  
/*  A sender MUST NOT send a Content-Length
986  
    header field in any message that contains
986  
    header field in any message that contains
987  
    a Transfer-Encoding header field.
987  
    a Transfer-Encoding header field.
988  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
988  
    https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
989  
*/
989  
*/
990  
    if( md.content_length.count > 0 &&
990  
    if( md.content_length.count > 0 &&
991  
        md.transfer_encoding.count > 0)
991  
        md.transfer_encoding.count > 0)
992  
    {
992  
    {
993  
        md.payload = payload::error;
993  
        md.payload = payload::error;
994  
        md.payload_size = 0;
994  
        md.payload_size = 0;
995  
        return;
995  
        return;
996  
    }
996  
    }
997  

997  

998  
    if(kind == detail::kind::response)
998  
    if(kind == detail::kind::response)
999  
        goto do_response;
999  
        goto do_response;
1000  

1000  

1001  
    //--------------------------------------------
1001  
    //--------------------------------------------
1002  

1002  

1003  
/*  The presence of a message body in a
1003  
/*  The presence of a message body in a
1004  
    request is signaled by a Content-Length
1004  
    request is signaled by a Content-Length
1005  
    or Transfer-Encoding header field. Request
1005  
    or Transfer-Encoding header field. Request
1006  
    message framing is independent of method
1006  
    message framing is independent of method
1007  
    semantics, even if the method does not
1007  
    semantics, even if the method does not
1008  
    define any use for a message body.
1008  
    define any use for a message body.
1009  
*/
1009  
*/
1010  
    if(md.content_length.count > 0)
1010  
    if(md.content_length.count > 0)
1011  
    {
1011  
    {
1012  
        if(md.content_length.value > 0)
1012  
        if(md.content_length.value > 0)
1013  
        {
1013  
        {
1014  
            // non-zero Content-Length
1014  
            // non-zero Content-Length
1015  
            md.payload = payload::size;
1015  
            md.payload = payload::size;
1016  
            md.payload_size = md.content_length.value;
1016  
            md.payload_size = md.content_length.value;
1017  
            return;
1017  
            return;
1018  
        }
1018  
        }
1019  
        // Content-Length: 0
1019  
        // Content-Length: 0
1020  
        md.payload = payload::none;
1020  
        md.payload = payload::none;
1021  
        md.payload_size = 0;
1021  
        md.payload_size = 0;
1022  
        return;
1022  
        return;
1023  
    }
1023  
    }
1024  
    if(md.transfer_encoding.is_chunked)
1024  
    if(md.transfer_encoding.is_chunked)
1025  
    {
1025  
    {
1026  
        // chunked
1026  
        // chunked
1027  
        md.payload = payload::chunked;
1027  
        md.payload = payload::chunked;
1028  
        md.payload_size = 0;
1028  
        md.payload_size = 0;
1029  
        return;
1029  
        return;
1030  
    }
1030  
    }
1031  
    // no payload
1031  
    // no payload
1032  
    md.payload = payload::none;
1032  
    md.payload = payload::none;
1033  
    md.payload_size = 0;
1033  
    md.payload_size = 0;
1034  
    return;
1034  
    return;
1035  

1035  

1036  
    //--------------------------------------------
1036  
    //--------------------------------------------
1037  
do_response:
1037  
do_response:
1038  

1038  

1039  
    if( res.status_int /  100 == 1 ||   // 1xx e.g. Continue
1039  
    if( res.status_int /  100 == 1 ||   // 1xx e.g. Continue
1040  
        res.status_int == 204 ||        // No Content
1040  
        res.status_int == 204 ||        // No Content
1041  
        res.status_int == 304)          // Not Modified
1041  
        res.status_int == 304)          // Not Modified
1042  
    {
1042  
    {
1043  
    /*  The correctness of any Content-Length
1043  
    /*  The correctness of any Content-Length
1044  
        here is defined by the particular
1044  
        here is defined by the particular
1045  
        resource, and cannot be determined
1045  
        resource, and cannot be determined
1046  
        here. In any case there is no payload.
1046  
        here. In any case there is no payload.
1047  
    */
1047  
    */
1048  
        md.payload = payload::none;
1048  
        md.payload = payload::none;
1049  
        md.payload_size = 0;
1049  
        md.payload_size = 0;
1050  
        return;
1050  
        return;
1051  
    }
1051  
    }
1052  
    if(md.content_length.count > 0)
1052  
    if(md.content_length.count > 0)
1053  
    {
1053  
    {
1054  
        if(md.content_length.value > 0)
1054  
        if(md.content_length.value > 0)
1055  
        {
1055  
        {
1056  
            // Content-Length > 0
1056  
            // Content-Length > 0
1057  
            md.payload = payload::size;
1057  
            md.payload = payload::size;
1058  
            md.payload_size = md.content_length.value;
1058  
            md.payload_size = md.content_length.value;
1059  
            return;
1059  
            return;
1060  
        }
1060  
        }
1061  
        // Content-Length: 0
1061  
        // Content-Length: 0
1062  
        md.payload = payload::none;
1062  
        md.payload = payload::none;
1063  
        md.payload_size = 0;
1063  
        md.payload_size = 0;
1064  
        return;
1064  
        return;
1065  
    }
1065  
    }
1066  
    if(md.transfer_encoding.is_chunked)
1066  
    if(md.transfer_encoding.is_chunked)
1067  
    {
1067  
    {
1068  
        // chunked
1068  
        // chunked
1069  
        md.payload = payload::chunked;
1069  
        md.payload = payload::chunked;
1070  
        md.payload_size = 0;
1070  
        md.payload_size = 0;
1071  
        return;
1071  
        return;
1072  
    }
1072  
    }
1073  

1073  

1074  
    // eof needed
1074  
    // eof needed
1075  
    md.payload = payload::to_eof;
1075  
    md.payload = payload::to_eof;
1076  
    md.payload_size = 0;
1076  
    md.payload_size = 0;
1077  
}
1077  
}
1078  

1078  

1079  
//------------------------------------------------
1079  
//------------------------------------------------
1080  

1080  

1081  
std::size_t
1081  
std::size_t
1082  
header::
1082  
header::
1083  
count_crlf(
1083  
count_crlf(
1084  
    core::string_view s) noexcept
1084  
    core::string_view s) noexcept
1085  
{
1085  
{
1086  
    auto it = s.data();
1086  
    auto it = s.data();
1087  
    auto len = s.size();
1087  
    auto len = s.size();
1088  
    std::size_t n = 0;
1088  
    std::size_t n = 0;
1089  
    while(len >= 2)
1089  
    while(len >= 2)
1090  
    {
1090  
    {
1091  
        if( it[0] == '\r' &&
1091  
        if( it[0] == '\r' &&
1092  
            it[1] != '\r')
1092  
            it[1] != '\r')
1093  
        {
1093  
        {
1094  
            if(it[1] == '\n')
1094  
            if(it[1] == '\n')
1095  
                n++;
1095  
                n++;
1096  
            it += 2;
1096  
            it += 2;
1097  
            len -= 2;
1097  
            len -= 2;
1098  
        }
1098  
        }
1099  
        else
1099  
        else
1100  
        {
1100  
        {
1101  
            it++;
1101  
            it++;
1102  
            len--;
1102  
            len--;
1103  
        }
1103  
        }
1104  
    }
1104  
    }
1105  
    return n;
1105  
    return n;
1106  
}
1106  
}
1107  

1107  

1108  
static
1108  
static
1109  
void
1109  
void
1110  
parse_start_line(
1110  
parse_start_line(
1111  
    header& h,
1111  
    header& h,
1112  
    header_limits const& lim,
1112  
    header_limits const& lim,
1113  
    std::size_t new_size,
1113  
    std::size_t new_size,
1114  
    system::error_code& ec) noexcept
1114  
    system::error_code& ec) noexcept
1115  
{
1115  
{
1116  
    BOOST_ASSERT(h.size == 0);
1116  
    BOOST_ASSERT(h.size == 0);
1117  
    BOOST_ASSERT(h.prefix == 0);
1117  
    BOOST_ASSERT(h.prefix == 0);
1118  
    BOOST_ASSERT(h.cbuf != nullptr);
1118  
    BOOST_ASSERT(h.cbuf != nullptr);
1119  
    BOOST_ASSERT(
1119  
    BOOST_ASSERT(
1120  
        h.kind != detail::kind::fields);
1120  
        h.kind != detail::kind::fields);
1121  

1121  

1122  
    auto const it0 = h.cbuf;
1122  
    auto const it0 = h.cbuf;
1123  
    auto const end = it0 + new_size;
1123  
    auto const end = it0 + new_size;
1124  
    char const* it = it0;
1124  
    char const* it = it0;
1125  
    if( new_size > lim.max_start_line)
1125  
    if( new_size > lim.max_start_line)
1126  
        new_size = lim.max_start_line;
1126  
        new_size = lim.max_start_line;
1127  
    if(h.kind == detail::kind::request)
1127  
    if(h.kind == detail::kind::request)
1128  
    {
1128  
    {
1129  
        auto rv = grammar::parse(
1129  
        auto rv = grammar::parse(
1130  
            it, end, request_line_rule);
1130  
            it, end, request_line_rule);
1131  
        if(! rv)
1131  
        if(! rv)
1132  
        {
1132  
        {
1133  
            ec = rv.error();
1133  
            ec = rv.error();
1134  
            if( ec == grammar::error::need_more &&
1134  
            if( ec == grammar::error::need_more &&
1135  
                new_size == lim.max_start_line)
1135  
                new_size == lim.max_start_line)
1136  
                ec = BOOST_HTTP_ERR(
1136  
                ec = BOOST_HTTP_ERR(
1137  
                    error::start_line_limit);
1137  
                    error::start_line_limit);
1138  
            return;
1138  
            return;
1139  
        }
1139  
        }
1140  
        // method
1140  
        // method
1141  
        auto sm = std::get<0>(*rv);
1141  
        auto sm = std::get<0>(*rv);
1142  
        h.req.method = string_to_method(sm);
1142  
        h.req.method = string_to_method(sm);
1143  
        h.req.method_len =
1143  
        h.req.method_len =
1144  
            static_cast<header::offset_type>(sm.size());
1144  
            static_cast<header::offset_type>(sm.size());
1145  
        // target
1145  
        // target
1146  
        auto st = std::get<1>(*rv);
1146  
        auto st = std::get<1>(*rv);
1147  
        h.req.target_len =
1147  
        h.req.target_len =
1148  
            static_cast<header::offset_type>(st.size());
1148  
            static_cast<header::offset_type>(st.size());
1149  
        // version
1149  
        // version
1150  
        switch(std::get<2>(*rv))
1150  
        switch(std::get<2>(*rv))
1151  
        {
1151  
        {
1152  
        case 10:
1152  
        case 10:
1153  
            h.version =
1153  
            h.version =
1154  
                http::version::http_1_0;
1154  
                http::version::http_1_0;
1155  
            break;
1155  
            break;
1156  
        case 11:
1156  
        case 11:
1157  
            h.version =
1157  
            h.version =
1158  
                http::version::http_1_1;
1158  
                http::version::http_1_1;
1159  
            break;
1159  
            break;
1160  
        default:
1160  
        default:
1161  
        {
1161  
        {
1162  
            ec = BOOST_HTTP_ERR(
1162  
            ec = BOOST_HTTP_ERR(
1163  
                error::bad_version);
1163  
                error::bad_version);
1164  
            return;
1164  
            return;
1165  
        }
1165  
        }
1166  
        }
1166  
        }
1167  
    }
1167  
    }
1168  
    else
1168  
    else
1169  
    {
1169  
    {
1170  
        auto rv = grammar::parse(
1170  
        auto rv = grammar::parse(
1171  
            it, end, status_line_rule);
1171  
            it, end, status_line_rule);
1172  
        if(! rv)
1172  
        if(! rv)
1173  
        {
1173  
        {
1174  
            ec = rv.error();
1174  
            ec = rv.error();
1175  
            if( ec == grammar::error::need_more &&
1175  
            if( ec == grammar::error::need_more &&
1176  
                new_size == lim.max_start_line)
1176  
                new_size == lim.max_start_line)
1177  
                ec = BOOST_HTTP_ERR(
1177  
                ec = BOOST_HTTP_ERR(
1178  
                    error::start_line_limit);
1178  
                    error::start_line_limit);
1179  
            return;
1179  
            return;
1180  
        }
1180  
        }
1181  
        // version
1181  
        // version
1182  
        switch(std::get<0>(*rv))
1182  
        switch(std::get<0>(*rv))
1183  
        {
1183  
        {
1184  
        case 10:
1184  
        case 10:
1185  
            h.version =
1185  
            h.version =
1186  
                http::version::http_1_0;
1186  
                http::version::http_1_0;
1187  
            break;
1187  
            break;
1188  
        case 11:
1188  
        case 11:
1189  
            h.version =
1189  
            h.version =
1190  
                http::version::http_1_1;
1190  
                http::version::http_1_1;
1191  
            break;
1191  
            break;
1192  
        default:
1192  
        default:
1193  
        {
1193  
        {
1194  
            ec = BOOST_HTTP_ERR(
1194  
            ec = BOOST_HTTP_ERR(
1195  
                error::bad_version);
1195  
                error::bad_version);
1196  
            return;
1196  
            return;
1197  
        }
1197  
        }
1198  
        }
1198  
        }
1199  
        // status-code
1199  
        // status-code
1200  
        h.res.status_int =
1200  
        h.res.status_int =
1201  
            static_cast<unsigned short>(
1201  
            static_cast<unsigned short>(
1202  
                std::get<1>(*rv).v);
1202  
                std::get<1>(*rv).v);
1203  
        h.res.status = std::get<1>(*rv).st;
1203  
        h.res.status = std::get<1>(*rv).st;
1204  
    }
1204  
    }
1205  
    h.prefix = static_cast<header::offset_type>(it - it0);
1205  
    h.prefix = static_cast<header::offset_type>(it - it0);
1206  
    h.size = h.prefix;
1206  
    h.size = h.prefix;
1207  
    h.on_start_line();
1207  
    h.on_start_line();
1208  
}
1208  
}
1209  

1209  

1210  
// returns: true if we added a field
1210  
// returns: true if we added a field
1211  
static
1211  
static
1212  
void
1212  
void
1213  
parse_field(
1213  
parse_field(
1214  
    header& h,
1214  
    header& h,
1215  
    header_limits const& lim,
1215  
    header_limits const& lim,
1216  
    std::size_t new_size,
1216  
    std::size_t new_size,
1217  
    system::error_code& ec) noexcept
1217  
    system::error_code& ec) noexcept
1218  
{
1218  
{
1219  
    if( new_size > lim.max_field)
1219  
    if( new_size > lim.max_field)
1220  
        new_size = lim.max_field;
1220  
        new_size = lim.max_field;
1221  
    auto const it0 = h.cbuf + h.size;
1221  
    auto const it0 = h.cbuf + h.size;
1222  
    auto const end = h.cbuf + new_size;
1222  
    auto const end = h.cbuf + new_size;
1223  
    char const* it = it0;
1223  
    char const* it = it0;
1224  
    auto rv = grammar::parse(
1224  
    auto rv = grammar::parse(
1225  
        it, end, field_rule);
1225  
        it, end, field_rule);
1226  
    if(rv.has_error())
1226  
    if(rv.has_error())
1227  
    {
1227  
    {
1228  
        ec = rv.error();
1228  
        ec = rv.error();
1229  
        if(ec == grammar::error::end_of_range)
1229  
        if(ec == grammar::error::end_of_range)
1230  
        {
1230  
        {
1231  
            // final CRLF
1231  
            // final CRLF
1232  
            h.size = static_cast<
1232  
            h.size = static_cast<
1233  
                header::offset_type>(it - h.cbuf);
1233  
                header::offset_type>(it - h.cbuf);
1234  
            return;
1234  
            return;
1235  
        }
1235  
        }
1236  
        if( ec == grammar::error::need_more &&
1236  
        if( ec == grammar::error::need_more &&
1237  
            new_size == lim.max_field)
1237  
            new_size == lim.max_field)
1238  
        {
1238  
        {
1239  
            ec = BOOST_HTTP_ERR(
1239  
            ec = BOOST_HTTP_ERR(
1240  
                error::field_size_limit);
1240  
                error::field_size_limit);
1241  
        }
1241  
        }
1242  
        return;
1242  
        return;
1243  
    }
1243  
    }
1244  
    if(h.count >= lim.max_fields)
1244  
    if(h.count >= lim.max_fields)
1245  
    {
1245  
    {
1246  
        ec = BOOST_HTTP_ERR(
1246  
        ec = BOOST_HTTP_ERR(
1247  
            error::fields_limit);
1247  
            error::fields_limit);
1248  
        return;
1248  
        return;
1249  
    }
1249  
    }
1250  
    if(rv->has_obs_fold)
1250  
    if(rv->has_obs_fold)
1251  
    {
1251  
    {
1252  
        // obs fold not allowed in test views
1252  
        // obs fold not allowed in test views
1253  
        BOOST_ASSERT(h.buf != nullptr);
1253  
        BOOST_ASSERT(h.buf != nullptr);
1254  
        remove_obs_fold(h.buf + h.size, it);
1254  
        remove_obs_fold(h.buf + h.size, it);
1255  
    }
1255  
    }
1256  
    auto id = string_to_field(rv->name)
1256  
    auto id = string_to_field(rv->name)
1257  
        .value_or(header::unknown_field);
1257  
        .value_or(header::unknown_field);
1258  
    h.size = static_cast<header::offset_type>(it - h.cbuf);
1258  
    h.size = static_cast<header::offset_type>(it - h.cbuf);
1259  

1259  

1260  
    // add field table entry
1260  
    // add field table entry
1261  
    if(h.buf != nullptr)
1261  
    if(h.buf != nullptr)
1262  
    {
1262  
    {
1263  
        auto& e = header::table(
1263  
        auto& e = header::table(
1264  
            h.buf + h.cap)[h.count];
1264  
            h.buf + h.cap)[h.count];
1265  
        auto const base =
1265  
        auto const base =
1266  
            h.buf + h.prefix;
1266  
            h.buf + h.prefix;
1267  
        e.np = static_cast<header::offset_type>(
1267  
        e.np = static_cast<header::offset_type>(
1268  
            rv->name.data() - base);
1268  
            rv->name.data() - base);
1269  
        e.nn = static_cast<header::offset_type>(
1269  
        e.nn = static_cast<header::offset_type>(
1270  
            rv->name.size());
1270  
            rv->name.size());
1271  
        e.vp = static_cast<header::offset_type>(
1271  
        e.vp = static_cast<header::offset_type>(
1272  
            rv->value.data() - base);
1272  
            rv->value.data() - base);
1273  
        e.vn = static_cast<header::offset_type>(
1273  
        e.vn = static_cast<header::offset_type>(
1274  
            rv->value.size());
1274  
            rv->value.size());
1275  
        e.id = id;
1275  
        e.id = id;
1276  
    }
1276  
    }
1277  
    ++h.count;
1277  
    ++h.count;
1278  
    h.on_insert(id, rv->value);
1278  
    h.on_insert(id, rv->value);
1279  
    ec = {};
1279  
    ec = {};
1280  
}
1280  
}
1281  

1281  

1282  
void
1282  
void
1283  
header::
1283  
header::
1284  
parse(
1284  
parse(
1285  
    std::size_t new_size,
1285  
    std::size_t new_size,
1286  
    header_limits const& lim,
1286  
    header_limits const& lim,
1287  
    system::error_code& ec) noexcept
1287  
    system::error_code& ec) noexcept
1288  
{
1288  
{
1289  
    if( new_size > lim.max_size)
1289  
    if( new_size > lim.max_size)
1290  
        new_size = lim.max_size;
1290  
        new_size = lim.max_size;
1291  
    if( this->prefix == 0 &&
1291  
    if( this->prefix == 0 &&
1292  
        this->kind !=
1292  
        this->kind !=
1293  
            detail::kind::fields)
1293  
            detail::kind::fields)
1294  
    {
1294  
    {
1295  
        parse_start_line(
1295  
        parse_start_line(
1296  
            *this, lim, new_size, ec);
1296  
            *this, lim, new_size, ec);
1297  
        if(ec)
1297  
        if(ec)
1298  
        {
1298  
        {
1299  
            if( ec == grammar::error::need_more &&
1299  
            if( ec == grammar::error::need_more &&
1300  
                new_size == lim.max_fields)
1300  
                new_size == lim.max_fields)
1301  
            {
1301  
            {
1302  
                ec = BOOST_HTTP_ERR(
1302  
                ec = BOOST_HTTP_ERR(
1303  
                    error::headers_limit);
1303  
                    error::headers_limit);
1304  
            }
1304  
            }
1305  
            return;
1305  
            return;
1306  
        }
1306  
        }
1307  
    }
1307  
    }
1308  
    for(;;)
1308  
    for(;;)
1309  
    {
1309  
    {
1310  
        parse_field(
1310  
        parse_field(
1311  
            *this, lim, new_size, ec);
1311  
            *this, lim, new_size, ec);
1312  
        if(ec)
1312  
        if(ec)
1313  
        {
1313  
        {
1314  
            if( ec == grammar::error::need_more &&
1314  
            if( ec == grammar::error::need_more &&
1315  
                new_size == lim.max_size)
1315  
                new_size == lim.max_size)
1316  
            {
1316  
            {
1317  
                ec = BOOST_HTTP_ERR(
1317  
                ec = BOOST_HTTP_ERR(
1318  
                    error::headers_limit);
1318  
                    error::headers_limit);
1319  
                return;
1319  
                return;
1320  
            }
1320  
            }
1321  
            break;
1321  
            break;
1322  
        }
1322  
        }
1323  
    }
1323  
    }
1324  
    if(ec == grammar::error::end_of_range)
1324  
    if(ec == grammar::error::end_of_range)
1325  
        ec = {};
1325  
        ec = {};
1326  
}
1326  
}
1327  

1327  

1328  
} // detail
1328  
} // detail
1329  
} // http
1329  
} // http
1330  
} // boost
1330  
} // boost