Skip to content

Commit

Permalink
field_rule_t uses field_name_t, field_value_t
Browse files Browse the repository at this point in the history
  • Loading branch information
cmazakas committed Feb 1, 2024
1 parent 8ae6ebe commit 0ff72c3
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 144 deletions.
4 changes: 2 additions & 2 deletions src/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ struct field_table

/*
From:
https://www.iana.org/assignments/message-headers/message-headers.xhtml
*/
field_table()
Expand Down Expand Up @@ -519,7 +519,7 @@ struct field_table
//

using const_iterator =
array_type::const_iterator;
array_type::const_iterator;

std::size_t
size() const
Expand Down
56 changes: 44 additions & 12 deletions src/fields_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <boost/http_proto/fields_base.hpp>

#include <boost/http_proto/error.hpp>
#include <boost/http_proto/field.hpp>
#include <boost/http_proto/header_limits.hpp>
#include <boost/http_proto/rfc/detail/rules.hpp>
Expand All @@ -21,6 +22,7 @@
#include <boost/assert/source_location.hpp>

#include <boost/url/grammar/ci_string.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/parse.hpp>
#include <boost/url/grammar/token_rule.hpp>

Expand Down Expand Up @@ -477,7 +479,11 @@ set(
auto rv = grammar::parse(
value, detail::field_value);
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover )
return error::bad_field_value;
return rv.error();
}

auto val = rv.value();
value = val.value;
Expand Down Expand Up @@ -601,7 +607,11 @@ set(
auto rv = grammar::parse(
value, detail::field_value);
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover )
return error::bad_field_value;
return rv.error();

Check warning on line 613 in src/fields_base.cpp

View check run for this annotation

Codecov / codecov/patch

src/fields_base.cpp#L613

Added line #L613 was not covered by tests
}

auto val = rv.value();
value = val.value;
Expand Down Expand Up @@ -637,15 +647,25 @@ set(
core::string_view name,
core::string_view value)
{
auto rv1 = grammar::parse(
name, detail::field_name);
if( rv1.has_error() )
return rv1.error();
{
auto rv = grammar::parse(
name, detail::field_name);
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover )
return error::bad_field_name;
return rv.error();
}
}

auto rv = grammar::parse(
value, detail::field_value);
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover )
return error::bad_field_value;
return rv.error();

Check warning on line 667 in src/fields_base.cpp

View check run for this annotation

Codecov / codecov/patch

src/fields_base.cpp#L667

Added line #L667 was not covered by tests
}

auto val = rv.value();
value = val.value;
Expand Down Expand Up @@ -821,17 +841,29 @@ insert_impl(
core::string_view value,
std::size_t before)
{
auto rv1 = grammar::parse(
name, detail::field_name);
if( rv1.has_error() )
return rv1.error();
{
auto rv = grammar::parse(
name, detail::field_name);
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover )
return error::bad_field_name;
return rv.error();
}
}

auto rv2 = grammar::parse(
auto rv = grammar::parse(
value, detail::field_value);
if( rv2.has_error() )
return rv2.error();
if( rv.has_error() )
{
if( rv.error() == urls::grammar::error::leftover)
return error::bad_field_value;
if( rv.error() == condition::need_more_input )
return error::bad_field_value;
return rv.error();
}

auto val = rv2.value();
auto val = rv.value();
insert_impl_unchecked(
id, name, val.value, before, val.has_obs_fold);

Expand Down
182 changes: 57 additions & 125 deletions src/rfc/detail/rules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@
// Official repository: https://github.com/cppalliance/http_proto
//

#include <boost/http_proto/detail/config.hpp>
#include <boost/http_proto/error.hpp>
#include <boost/http_proto/rfc/detail/rules.hpp>

#include <boost/http_proto/error.hpp>
#include <boost/http_proto/detail/config.hpp>
#include <boost/http_proto/rfc/token_rule.hpp>

#include <boost/core/detail/string_view.hpp>
#include <boost/url/grammar/delim_rule.hpp>
#include <boost/url/grammar/digit_chars.hpp>
#include <boost/url/grammar/error.hpp>
#include <boost/url/grammar/lut_chars.hpp>
#include <boost/url/grammar/parse.hpp>
#include <boost/url/grammar/tuple_rule.hpp>

namespace boost {
namespace http_proto {
Expand All @@ -35,7 +39,7 @@ struct ws_field_vchar_t
}
};

constexpr ws_field_vchar_t ws_field_vchar{};
// constexpr ws_field_vchar_t ws_field_vchar{};

auto
crlf_rule_t::
Expand Down Expand Up @@ -201,23 +205,30 @@ parse(
auto
field_name_t::
parse(
char const *&it,
char const *end) const noexcept ->
char const*& it,
char const* end) const noexcept ->
system::result<value_type>
{
if( it == end )
BOOST_HTTP_PROTO_RETURN_EC(grammar::error::need_more);
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);

value_type v;
auto s0 = it;
while( it < end )

auto begin = it;
auto rv = grammar::parse(
it, end, token_rule);
if( rv.has_error() || (it != end) )
{
auto ch = *it;
if (! tchars(ch) )
BOOST_HTTP_PROTO_RETURN_EC(error::bad_field_name);
++it;
if( it != begin )
{
v.name = core::string_view(begin, it - begin);
return v;
}
return error::bad_field_name;
}
v.name = core::string_view(s0, it - end);

v.name = core::string_view(begin, end - begin);
return v;
}

Expand Down Expand Up @@ -265,23 +276,39 @@ parse(
{
// too short to contain valid obs-fold sequence
if( end - it < 3 )
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);
}


if( it[1] != '\n' )
{
if( s0 ) goto done;
BOOST_HTTP_PROTO_RETURN_EC(
http_proto::error::bad_field_value);
}

if(! ws(it[2]) )
{
if( s0 ) goto done;

if( !s0 )
{
s0 = it;
s1 = s0;
goto done;
}

// only report this to the user when we can reasonably
// determine that a header was smuggled inside our `value`
// which happens when we see `crlf tchar` as
// `field-name = 1*tchar`
if( tchars(it[2]) )

Check warning on line 307 in src/rfc/detail/rules.cpp

View check run for this annotation

Codecov / codecov/patch

src/rfc/detail/rules.cpp#L307

Added line #L307 was not covered by tests
{
BOOST_HTTP_PROTO_RETURN_EC(

Check warning on line 309 in src/rfc/detail/rules.cpp

View check run for this annotation

Codecov / codecov/patch

src/rfc/detail/rules.cpp#L309

Added line #L309 was not covered by tests
http_proto::error::bad_field_smuggle);
}

BOOST_HTTP_PROTO_RETURN_EC(

Check warning on line 313 in src/rfc/detail/rules.cpp

View check run for this annotation

Codecov / codecov/patch

src/rfc/detail/rules.cpp#L313

Added line #L313 was not covered by tests
http_proto::error::bad_field_value);
Expand All @@ -292,8 +319,12 @@ parse(
}

if(! is_field_vchar(ch) )
{
if( s0 ) goto done;

BOOST_HTTP_PROTO_RETURN_EC(
http_proto::error::bad_field_value);
}

if(! s0 )
s0 = it;
Expand All @@ -302,6 +333,7 @@ parse(
s1 = it;
}

done:
v.value = core::string_view(s0, s1 - s0);
return v;
}
Expand Down Expand Up @@ -339,121 +371,21 @@ parse(
}

value_type v;
auto rv = grammar::parse(
it, end, grammar::tuple_rule(
field_name,
grammar::delim_rule(':'),
field_value,
crlf_rule));

// field name
{
auto rv = grammar::parse(
it, end, grammar::tuple_rule(
token_rule,
grammar::squelch(
grammar::delim_rule(':'))));
if(! rv)
return rv.error();
v.name = rv.value();
}
if( rv.has_error() )
return rv.error();

// consume all obs-fold until field char or end of field:
//
// HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ]
// header-field = field-name ":" OWS field-value OWS
// field-value = *( field-content / obs-fold )
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
// obs-fold = CRLF 1*( SP / HTAB )
//
for(;;)
{
skip_ows(it, end);
if(it == end)
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);
}
if(*it != '\r')
{
// start of value
break;
}
++it;
if(it == end)
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);
}
if(*it != '\n')
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::mismatch);
}
++it;
if(it == end)
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);
}
// FIXME: this should be a loop of some kind as we've detected a valid
// CRLF at this stage but need to account for the ABNF specifying:
// obs-fold = CRLF 1*( SP / HTAB )
if(*it != ' ' &&
*it != '\t')
{
// because we saw a CRLF and didn't see the required SP / HTAB,
// we know we have a zero length field value
v.value = core::string_view(it, 0);
return v;
}
// eat obs-fold
++it;
v.has_obs_fold = true;
}
auto val = rv.value();
v.name = std::get<0>(val).name;
v.value = std::get<2>(val).value;
v.has_obs_fold = std::get<2>(val).has_obs_fold;

char const* s0 = it; // start of value
for(;;)
{
auto rv = grammar::parse(
it, end, grammar::tuple_rule(
grammar::token_rule(
ws_field_vchar),
crlf_rule));
if(! rv)
return rv.error();
if(it == end)
{
BOOST_HTTP_PROTO_RETURN_EC(
grammar::error::need_more);
}
if( *it != ' ' &&
*it != '\t')
{
// end of field
break;
}
// *it will match field_value_rule
v.has_obs_fold = true;
}

v.value = core::string_view(s0, (it - s0) - 2);
BOOST_ASSERT(! v.value.empty());
//BOOST_ASSERT(! ws(t.v.value.front()));

// remove trailing SP,HTAB,CR,LF
auto p = &v.value.back();
for(;;)
{
switch(*p)
{
case ' ': case '\t':
case '\r': case '\n':
--p;
continue;
default:
++p;
goto done;
}
}
done:
v.value = core::string_view(
v.value.data(),
p - v.value.data());
return v;
}

Expand Down
Loading

0 comments on commit 0ff72c3

Please sign in to comment.