src/detail/grammar.hpp
100.0% Lines (91/91)
100.0% List of functions (15/15)
98.5% Branches (67/68)
Functions (15)
Function
Calls
Lines
Branches
Blocks
unsigned long boost::burl::detail::distance<unsigned long>(char const*, char const*)
:30
591113x
100.0%
–
100.0%
unsigned short boost::burl::detail::distance<unsigned short>(char const*, char const*)
:30
44363x
100.0%
–
100.0%
boost::burl::detail::trim_front(char const*, char const*)
:39
17727x
100.0%
100.0%
100.0%
boost::burl::detail::trim_back(char const*, char const*)
:53
17727x
100.0%
83.3%
100.0%
boost::burl::detail::is_token_char(char)
:68
274991x
100.0%
–
100.0%
boost::burl::detail::is_print(char)
:100
360800x
100.0%
–
100.0%
boost::burl::detail::is_target_char(char)
:107
117886x
100.0%
100.0%
100.0%
boost::burl::detail::is_digit(char)
:115
1773x
100.0%
100.0%
100.0%
boost::burl::detail::parse_token_to_eol(char const*, char const*, char const*&, std::error_code&)
:122
31554x
100.0%
100.0%
100.0%
boost::burl::detail::parse_field(char const*&, char const*, std::basic_string_view<char, std::char_traits<char> >&, std::basic_string_view<char, std::char_traits<char> >&, std::error_code&)
:173
36540x
100.0%
100.0%
100.0%
void boost::burl::detail::parse_limited<boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#1}>(boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#1}&&, char const*&, char const*, unsigned long, boost::http::error, std::error_code&)
:250
80694x
100.0%
100.0%
100.0%
void boost::burl::detail::parse_limited<boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#2}>(boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#2}&&, char const*&, char const*, unsigned long, boost::http::error, std::error_code&)
:250
38362x
100.0%
100.0%
100.0%
void boost::burl::detail::parse_limited<boost::burl::head_parser::parse_fields_(char const*&, char const*, std::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#1}>(boost::burl::head_parser::parse_fields_(char const*&, char const*, std::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#1}&&, char const*&, char const*, unsigned long, boost::http::error, std::error_code&)
:250
36386x
100.0%
100.0%
100.0%
void boost::burl::detail::parse_limited<boost::burl::parser::parse_trailer(boost::burl::fields_base&)::{lambda(auto:1&, auto:2, auto:3&)#1}>(boost::burl::parser::parse_trailer(boost::burl::fields_base&)::{lambda(auto:1&, auto:2, auto:3&)#1}&&, char const*&, char const*, unsigned long, boost::http::error, std::error_code&)
:250
154x
100.0%
–
100.0%
boost::burl::detail::parse_limited<boost::burl::parser::parse_trailer(boost::burl::fields_base&)::{lambda(auto:1&, auto:2, auto:3&)#1}>(boost::burl::parser::parse_trailer(boost::burl::fields_base&)::{lambda(auto:1&, auto:2, auto:3&)#1}&&, char const*&, char const*, unsigned long, boost::http::error, std::error_code&)::{lambda()#1}::operator()() const
:258
154x
100.0%
100.0%
100.0%
| Line | Branch | TLA | Hits | Source Code |
|---|---|---|---|---|
| 1 | // | |||
| 2 | // Copyright (c) 2021 Vinnie Falco ([email protected]) | |||
| 3 | // Copyright (c) 2026 Mohammad Nejati | |||
| 4 | // | |||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||
| 7 | // | |||
| 8 | // Official repository: https://github.com/cppalliance/burl | |||
| 9 | // | |||
| 10 | ||||
| 11 | #ifndef BOOST_BURL_SRC_DETAIL_GRAMMAR_HPP | |||
| 12 | #define BOOST_BURL_SRC_DETAIL_GRAMMAR_HPP | |||
| 13 | ||||
| 14 | #include <boost/config.hpp> | |||
| 15 | #include <boost/http/error.hpp> | |||
| 16 | #include <system_error> | |||
| 17 | ||||
| 18 | #include <cstddef> | |||
| 19 | #include <string_view> | |||
| 20 | ||||
| 21 | namespace boost | |||
| 22 | { | |||
| 23 | namespace burl | |||
| 24 | { | |||
| 25 | namespace detail | |||
| 26 | { | |||
| 27 | ||||
| 28 | template<class T = std::size_t> | |||
| 29 | T | |||
| 30 | 635476x | distance( | ||
| 31 | char const* it, | |||
| 32 | char const* end) noexcept | |||
| 33 | { | |||
| 34 | 635476x | return static_cast<T>(end - it); | ||
| 35 | } | |||
| 36 | ||||
| 37 | inline | |||
| 38 | char const* | |||
| 39 | 17727x | trim_front( | ||
| 40 | char const* it, char const* end) noexcept | |||
| 41 | { | |||
| 42 |
2/2✓ Branch 0 taken 35452 times.
✓ Branch 1 taken 7 times.
|
35459x | while(it != end) | |
| 43 | { | |||
| 44 |
4/4✓ Branch 0 taken 17721 times.
✓ Branch 1 taken 17731 times.
✓ Branch 2 taken 17720 times.
✓ Branch 3 taken 1 time.
|
35452x | if(*it != ' ' && *it != '\t') | |
| 45 | 17720x | break; | ||
| 46 | 17732x | ++it; | ||
| 47 | } | |||
| 48 | 17727x | return it; | ||
| 49 | } | |||
| 50 | ||||
| 51 | inline | |||
| 52 | char const* | |||
| 53 | 17727x | trim_back( | ||
| 54 | char const* it, char const* first) noexcept | |||
| 55 | { | |||
| 56 |
2/2✓ Branch 0 taken 17724 times.
✓ Branch 1 taken 7 times.
|
17731x | while(it != first) | |
| 57 | { | |||
| 58 | 17724x | auto const c = it[-1]; | ||
| 59 |
3/4✓ Branch 0 taken 17720 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 17720 times.
✗ Branch 3 not taken.
|
17724x | if(c != ' ' && c != '\t') | |
| 60 | 17720x | break; | ||
| 61 | 4x | --it; | ||
| 62 | } | |||
| 63 | 17727x | return it; | ||
| 64 | } | |||
| 65 | ||||
| 66 | inline | |||
| 67 | bool | |||
| 68 | 274991x | is_token_char(char c) noexcept | ||
| 69 | { | |||
| 70 | /* | |||
| 71 | tchar = "!" | "#" | "$" | "%" | "&" | | |||
| 72 | "'" | "*" | "+" | "-" | "." | | |||
| 73 | "^" | "_" | "`" | "|" | "~" | | |||
| 74 | DIGIT | ALPHA | |||
| 75 | */ | |||
| 76 | static char constexpr tab[] = { | |||
| 77 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 | |||
| 78 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 | |||
| 79 | 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 | |||
| 80 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 | |||
| 81 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 | |||
| 82 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 | |||
| 83 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 | |||
| 84 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112 | |||
| 85 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 | |||
| 86 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144 | |||
| 87 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 | |||
| 88 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176 | |||
| 89 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 | |||
| 90 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208 | |||
| 91 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224 | |||
| 92 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240 | |||
| 93 | }; | |||
| 94 | static_assert(sizeof(tab) == 256); | |||
| 95 | 274991x | return tab[static_cast<unsigned char>(c)]; | ||
| 96 | } | |||
| 97 | ||||
| 98 | inline | |||
| 99 | bool | |||
| 100 | 360800x | is_print(char c) noexcept | ||
| 101 | { | |||
| 102 | 360800x | return static_cast<unsigned char>(c-32) < 95; | ||
| 103 | } | |||
| 104 | ||||
| 105 | inline | |||
| 106 | bool | |||
| 107 | 117886x | is_target_char(char c) noexcept | ||
| 108 | { | |||
| 109 | 117886x | auto const u = static_cast<unsigned char>(c); | ||
| 110 |
4/4✓ Branch 0 taken 83511 times.
✓ Branch 1 taken 34375 times.
✓ Branch 2 taken 83509 times.
✓ Branch 3 taken 2 times.
|
117886x | return u >= 0x21 && u <= 0x7e; | |
| 111 | } | |||
| 112 | ||||
| 113 | inline | |||
| 114 | bool | |||
| 115 | 1773x | is_digit(char c) noexcept | ||
| 116 | { | |||
| 117 |
4/4✓ Branch 0 taken 1771 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1767 times.
✓ Branch 3 taken 4 times.
|
1773x | return c >= '0' && c <= '9'; | |
| 118 | } | |||
| 119 | ||||
| 120 | inline | |||
| 121 | char const* | |||
| 122 | 31554x | parse_token_to_eol( | ||
| 123 | char const* it, | |||
| 124 | char const* end, | |||
| 125 | char const*& token_end, | |||
| 126 | std::error_code& ec) noexcept | |||
| 127 | { | |||
| 128 | 338795x | for(;; ++it) | ||
| 129 | { | |||
| 130 |
2/2✓ Branch 0 taken 9549 times.
✓ Branch 1 taken 360800 times.
|
370349x | if(it >= end) | |
| 131 | { | |||
| 132 | 9549x | ec = http::error::need_data; | ||
| 133 | 9549x | return it; | ||
| 134 | } | |||
| 135 |
2/2✓ Branch 1 taken 22008 times.
✓ Branch 2 taken 338792 times.
|
360800x | if(BOOST_UNLIKELY(! is_print(*it))) | |
| 136 |
2/2✓ Branch 0 taken 22006 times.
✓ Branch 1 taken 2 times.
|
22008x | if((BOOST_LIKELY(static_cast< | |
| 137 | 22006x | unsigned char>(*it) < '\040') && | ||
| 138 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 22003 times.
|
22006x | BOOST_LIKELY(*it != 9)) || | |
| 139 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5x | BOOST_UNLIKELY(*it == 127)) | |
| 140 | 22005x | goto found_control; | ||
| 141 | } | |||
| 142 | 22005x | found_control: | ||
| 143 |
2/2✓ Branch 0 taken 21996 times.
✓ Branch 1 taken 9 times.
|
22005x | if(BOOST_LIKELY(*it == '\r')) | |
| 144 | { | |||
| 145 |
2/2✓ Branch 0 taken 1278 times.
✓ Branch 1 taken 20718 times.
|
21996x | if(++it >= end) | |
| 146 | { | |||
| 147 | 1278x | ec = http::error::need_data; | ||
| 148 | 1278x | return end; | ||
| 149 | } | |||
| 150 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20716 times.
|
20718x | if(*it++ != '\n') | |
| 151 | { | |||
| 152 | 2x | ec = http::error::bad_line_ending; | ||
| 153 | 2x | return end; | ||
| 154 | } | |||
| 155 | 20716x | token_end = it - 2; | ||
| 156 | } | |||
| 157 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9x | else if(*it == '\n') | |
| 158 | { | |||
| 159 | // bare LF | |||
| 160 | 3x | ec = http::error::bad_line_ending; | ||
| 161 | 3x | return end; | ||
| 162 | } | |||
| 163 | else | |||
| 164 | { | |||
| 165 | // invalid character | |||
| 166 | 6x | return nullptr; | ||
| 167 | } | |||
| 168 | 20716x | return it; | ||
| 169 | } | |||
| 170 | ||||
| 171 | inline | |||
| 172 | void | |||
| 173 | 36540x | parse_field( | ||
| 174 | char const*& it, | |||
| 175 | char const* end, | |||
| 176 | std::string_view& name, | |||
| 177 | std::string_view& value, | |||
| 178 | std::error_code& ec) | |||
| 179 | { | |||
| 180 | /* header-field = field-name ":" OWS field-value OWS | |||
| 181 | ||||
| 182 | field-name = token | |||
| 183 | field-value = *( field-content / obs-fold ) | |||
| 184 | field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] | |||
| 185 | field-vchar = VCHAR / obs-text | |||
| 186 | ||||
| 187 | obs-fold = CRLF 1*( SP / HTAB ) | |||
| 188 | ; obsolete line folding | |||
| 189 | ; see Section 3.2.4 | |||
| 190 | ||||
| 191 | token = 1*<any CHAR except CTLs or separators> | |||
| 192 | CHAR = <any US-ASCII character (octets 0 - 127)> | |||
| 193 | sep = "(" | ")" | "<" | ">" | "@" | |||
| 194 | | "," | ";" | ":" | "\" | <"> | |||
| 195 | | "/" | "[" | "]" | "?" | "=" | |||
| 196 | | "{" | "}" | SP | HT | |||
| 197 | */ | |||
| 198 | ||||
| 199 | 36540x | auto first = it; | ||
| 200 |
6/6✓ Branch 0 taken 123615 times.
✓ Branch 1 taken 5572 times.
✓ Branch 3 taken 92647 times.
✓ Branch 4 taken 30968 times.
✓ Branch 5 taken 92647 times.
✓ Branch 6 taken 36540 times.
|
129187x | while(it != end && is_token_char(*it)) | |
| 201 | { | |||
| 202 | 92647x | ++it; | ||
| 203 | } | |||
| 204 |
2/2✓ Branch 0 taken 5572 times.
✓ Branch 1 taken 30968 times.
|
36540x | if(it == end) | |
| 205 | { | |||
| 206 | 5572x | ec = http::error::need_data; | ||
| 207 | 5572x | return; | ||
| 208 | } | |||
| 209 |
4/4✓ Branch 0 taken 30964 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 30959 times.
|
30968x | if(it == first || *it != ':') | |
| 210 | { | |||
| 211 | 9x | ec = http::error::bad_field_name; | ||
| 212 | 9x | return; | ||
| 213 | } | |||
| 214 | 30959x | name = { first, it }; | ||
| 215 | 30959x | ++it; // eat ':' | ||
| 216 | 30959x | first = it; | ||
| 217 | 30959x | char const* token_end = nullptr; | ||
| 218 | for(;;) | |||
| 219 | { | |||
| 220 | // parse to CRLF | |||
| 221 | 30969x | it = parse_token_to_eol(it, end, token_end, ec); | ||
| 222 |
2/2✓ Branch 1 taken 10580 times.
✓ Branch 2 taken 20389 times.
|
30969x | if(ec) | |
| 223 | 10580x | return; | ||
| 224 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20385 times.
|
20389x | if(! it) | |
| 225 | { | |||
| 226 | 4x | ec = http::error::bad_field_value; | ||
| 227 | 4x | return; | ||
| 228 | } | |||
| 229 | // Look 1 char past the CRLF to handle obs-fold. | |||
| 230 |
2/2✓ Branch 0 taken 2648 times.
✓ Branch 1 taken 17737 times.
|
20385x | if(it == end) | |
| 231 | { | |||
| 232 | 2648x | ec = http::error::need_data; | ||
| 233 | 2648x | return; | ||
| 234 | } | |||
| 235 |
4/4✓ Branch 0 taken 17729 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 17727 times.
✓ Branch 3 taken 2 times.
|
17737x | if(*it != ' ' && *it != '\t') | |
| 236 | { | |||
| 237 | 17727x | first = trim_front(first, token_end); | ||
| 238 | 17727x | value = { first, trim_back(token_end, first) }; | ||
| 239 | 17727x | return; | ||
| 240 | } | |||
| 241 | // obs-fold: resolve in place, CRLF -> SP SP | |||
| 242 | 10x | auto const q = const_cast<char*>(it); | ||
| 243 | 10x | q[-2] = ' '; | ||
| 244 | 10x | q[-1] = ' '; | ||
| 245 | 10x | } | ||
| 246 | } | |||
| 247 | ||||
| 248 | template<class Parse> | |||
| 249 | void | |||
| 250 | 155596x | parse_limited( | ||
| 251 | Parse&& parse, | |||
| 252 | char const*& it, | |||
| 253 | char const* end, | |||
| 254 | std::size_t limit, | |||
| 255 | http::error limit_err, | |||
| 256 | std::error_code& ec) noexcept | |||
| 257 | { | |||
| 258 | 311346x | bool const limited = [&]() | ||
| 259 | { | |||
| 260 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 152 times.
|
154x | if(distance(it, end) >= limit) | |
| 261 | { | |||
| 262 | 2x | end = it + limit; | ||
| 263 | 2x | return true; | ||
| 264 | } | |||
| 265 | 152x | return false; | ||
| 266 | 155596x | }(); | ||
| 267 | 155596x | parse(it, end, ec); | ||
| 268 |
6/6✓ Branch 2 taken 87832 times.
✓ Branch 3 taken 67764 times.
✓ Branch 4 taken 23357 times.
✓ Branch 5 taken 64475 times.
✓ Branch 6 taken 23357 times.
✓ Branch 7 taken 132239 times.
|
155596x | if(ec == http::error::need_data && limited) | |
| 269 | 23357x | ec = limit_err; | ||
| 270 | 155596x | } | ||
| 271 | ||||
| 272 | } // namespace detail | |||
| 273 | } // namespace burl | |||
| 274 | } // namespace boost | |||
| 275 | ||||
| 276 | #endif | |||
| 277 |