Skip to content

Commit

Permalink
expect handles presence of request content
Browse files Browse the repository at this point in the history
  • Loading branch information
cmazakas committed Feb 15, 2024
1 parent 004e95c commit 2fdc538
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 15 deletions.
10 changes: 10 additions & 0 deletions include/boost/http_proto/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,16 @@ enum class error
*/
body_too_large,

/** Expect needs content
The parser found a valid Expect
header but has not yet found
a field that defines the request
as having either a content-length
or a chunked transfer-encoding
*/
expect_needs_content,

/** Headers too large.
*
The combined size of the start line and
Expand Down
48 changes: 40 additions & 8 deletions src/detail/header.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2019 Vinnie Falco ([email protected])
// Copyright (c) 2024 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -8,6 +9,7 @@
//

#include <boost/http_proto/detail/header.hpp>
#include <boost/http_proto/error.hpp>
#include <boost/http_proto/field.hpp>
#include <boost/http_proto/fields_view_base.hpp>
#include <boost/http_proto/header_limits.hpp>
Expand All @@ -24,7 +26,6 @@
#include <boost/assert.hpp>
#include <boost/assert/source_location.hpp>
#include <boost/static_assert.hpp>
#include <string>
#include <utility>

namespace boost {
Expand Down Expand Up @@ -524,6 +525,11 @@ on_insert_content_length(
// one value
md.content_length.ec = {};
md.content_length.value = *rv;
if( md.expect.ec == error::expect_needs_content )
{
md.expect.ec = {};
md.expect.is_100_continue = true;
}
update_payload();
return;
}
Expand All @@ -548,16 +554,25 @@ on_insert_expect(
++md.expect.count;
if(kind != detail::kind::request)
return;
if(md.expect.ec.failed())
return;

// VFALCO Should we allow duplicate
// Expect fields that have 100-continue?

// TODO: we need to add content checks
// i.e. does the request have either `content-length`
// or a `transfer-encoding: chunked`.
// https://datatracker.ietf.org/doc/html/rfc9110#section-10.1.1-10
// https://datatracker.ietf.org/doc/html/rfc9110#section-10.1.1-11.1
// A client MUST NOT generate a 100-continue expectation in a
// request that does not include content.
auto const has_content = [&]
{
auto const has_content_length =
md.content_length.count > 0 &&
!md.content_length.ec.failed();

auto const is_chunked =
md.transfer_encoding.is_chunked;

return has_content_length ||
is_chunked;
}();

if( md.expect.count > 1 ||
! grammar::ci_is_equal(v,
Expand All @@ -569,6 +584,16 @@ on_insert_expect(
md.expect.is_100_continue = false;
return;
}

if(! has_content )
{
md.expect.ec =
BOOST_HTTP_PROTO_ERR(
error::expect_needs_content);
md.expect.is_100_continue = false;
return;
}

md.expect.is_100_continue = true;
}

Expand Down Expand Up @@ -606,7 +631,14 @@ on_insert_transfer_encoding()
if(! md.transfer_encoding.is_chunked)
{
if(t.id == transfer_coding::chunked)
{
md.transfer_encoding.is_chunked = true;
if( md.expect.ec == error::expect_needs_content )
{
md.expect.ec = {};
md.expect.is_100_continue = true;
}
}
continue;
}
if(t.id == transfer_coding::chunked)
Expand Down Expand Up @@ -758,7 +790,7 @@ on_erase_expect()
return;
*/
// reset and re-insert
auto n = md.expect.count;
auto n = count;
auto const p = cbuf + prefix;
auto const* e = &tab()[0];
md.expect = {};
Expand Down
108 changes: 108 additions & 0 deletions test/unit/fields_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,27 +1087,66 @@ struct fields_base_test
{ {}, 1, true },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n");

check(
{ {}, 1, true },
"POST / HTTP/1.1\r\n"
"Transfer-Encoding: chunked\r\n"
"Expect: 100-continue\r\n"
"\r\n");

check(
{ {}, 1, true },
"POST / HTTP/1.1\r\n"
"Content-Length: 1234\r\n"
"Expect: 100-continue\r\n"
"\r\n");

check(
{ {}, 1, true },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Content-Length: 1234\r\n"
"\r\n");

check(
{ error::bad_expect, 1, false },
"POST / HTTP/1.1\r\n"
"Expect: 100-continueish\r\n"
"Content-Length: 1234\r\n"
"\r\n");

check(
{ error::bad_expect, 2, false },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Expect: 100-continue\r\n"
"Content-Length: 1234\r\n"
"\r\n");

check(
{ error::bad_expect, 2, false },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Expect: 100-continue\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n");

check(
{ error::bad_expect, 2, false },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Content-Length: 1234\r\n"
"Expect: 404-not-found\r\n"
"\r\n");

check(
{ error::expect_needs_content, 1, false },
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"\r\n");
}

// parse response
Expand Down Expand Up @@ -1240,6 +1279,7 @@ struct fields_base_test
req.count(field::expect), 1);
},
"POST / HTTP/1.1\r\n"
"Content-Length: 1234\r\n"
"Expect: 100-continue\r\n"
"Expect: 100-continue\r\n"
"\r\n");
Expand Down Expand Up @@ -1273,6 +1313,7 @@ struct fields_base_test
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Expect: 404-not-found\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n");

// set
Expand All @@ -1299,6 +1340,7 @@ struct fields_base_test
},
"POST / HTTP/1.1\r\n"
"Expect: 100-continueish\r\n"
"Content-Length: 1234\r\n"
"\r\n");

check(
Expand All @@ -1310,9 +1352,75 @@ struct fields_base_test
"100-continue");
},
"POST / HTTP/1.1\r\n"
"Content-Length: 1234\r\n"
"Expect: 500-server-error\r\n"
"Expect: 404-not-found\r\n"
"\r\n");

// erase + set

check(
{ {}, 1, true },
[](request& req)
{
BOOST_TEST_EQ(
req.metadata().expect.ec,
error::bad_expect);

req.erase(req.find(field::expect));

BOOST_TEST_EQ(
req.metadata().expect.ec,
error::expect_needs_content);

req.set_content_length(1234);
},
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Expect: 100-continue\r\n"
"\r\n");

check(
{ {}, 1, true },
[](request& req)
{
BOOST_TEST_EQ(
req.metadata().expect.ec,
error::bad_expect);

req.erase(req.find(field::expect));

BOOST_TEST_EQ(
req.metadata().expect.ec,
error::expect_needs_content);

req.set_content_length(1234);
},
"POST / HTTP/1.1\r\n"
"Expect: 101-dalmations\r\n"
"Expect: 100-continue\r\n"
"\r\n");

check(
{ {}, 1, true },
[](request& req)
{
BOOST_TEST_EQ(
req.metadata().expect.ec,
error::bad_expect);

req.erase(req.find(field::expect));

BOOST_TEST_EQ(
req.metadata().expect.ec,
error::expect_needs_content);

req.set_content_length(1234);
},
"POST / HTTP/1.1\r\n"
"Expect: 101-dalmations\r\n"
"Expect: 100-continue\r\n"
"\r\n");
}
}

Expand Down
39 changes: 32 additions & 7 deletions test/unit/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,23 +469,48 @@ struct request_test
request req;
req.set_expect_100_continue(true);
BOOST_TEST(
req.metadata().expect.is_100_continue);
req.metadata().expect.ec.failed());
}

{
request req;
req.set_expect_100_continue(false);
BOOST_TEST(
!req.metadata().expect.is_100_continue);
BOOST_TEST(
!req.metadata().expect.ec.failed());
}

auto make_request = []
{
request req(
"POST / HTTP/1.1\r\n"
"content-length: 1234\r\n"
"\r\n");

return req;
};

{
request req;
request req = make_request();
req.set_expect_100_continue(true);
BOOST_TEST(
req.metadata().expect.is_100_continue);

req.set_expect_100_continue(false);
BOOST_TEST(
!req.metadata().expect.is_100_continue);
}

{
request req;
request req = make_request();
req.set_expect_100_continue(false);
BOOST_TEST(
!req.metadata().expect.is_100_continue);
}

{
request req = make_request();
req.set_expect_100_continue(true);
BOOST_TEST(
req.metadata().expect.is_100_continue);
Expand All @@ -496,7 +521,7 @@ struct request_test
}

{
request req;
request req = make_request();
BOOST_TEST(
!req.metadata().expect.ec.failed());

Expand All @@ -510,7 +535,7 @@ struct request_test
}

{
request req;
request req = make_request();
req.append("Expect", "100-continue");
req.append("Expect", "101-dalmations");

Expand All @@ -527,7 +552,7 @@ struct request_test
}

{
request req;
request req = make_request();
req.append("Expect", "100-continue");
req.append("Expect", "100-continue");

Expand All @@ -544,7 +569,7 @@ struct request_test
}

{
request req;
request req = make_request();
req.append("Expect", "100-continue");
req.append("Expect", "100-continue");

Expand Down

0 comments on commit 2fdc538

Please sign in to comment.