Skip to content

Commit 2541e0c

Browse files
committed
add unit tests for read operations
1 parent 716a55c commit 2541e0c

File tree

3 files changed

+188
-74
lines changed

3 files changed

+188
-74
lines changed

include/boost/http_io/impl/read.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//
22
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3+
// Copyright (c) 2025 Mohammad Nejati
34
//
45
// Distributed under the Boost Software License, Version 1.0. (See accompanying
56
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -62,7 +63,15 @@ class read_until_op
6263
{
6364
pr_.parse(ec);
6465
if(ec == http_proto::condition::need_more_input)
66+
{
67+
// specific to http_io::async_read_some
68+
if(total_bytes_ != 0 && condition_(pr_))
69+
{
70+
ec = {};
71+
goto upcall;
72+
}
6573
break;
74+
}
6675
if(ec.failed() || condition_(pr_))
6776
{
6877
if(total_bytes_ == 0)

include/boost/http_io/read.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//
22
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3+
// Copyright (c) 2025 Mohammad Nejati
34
//
45
// Distributed under the Boost Software License, Version 1.0. (See accompanying
56
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

test/unit/read.cpp

Lines changed: 178 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//
22
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3+
// Copyright (c) 2025 Mohammad Nejati
34
//
45
// Distributed under the Boost Software License, Version 1.0. (See accompanying
56
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -10,99 +11,202 @@
1011
// Test that header file is self-contained.
1112
#include <boost/http_io/read.hpp>
1213

14+
#include <boost/http_io/test/handler.hpp>
15+
#include <boost/http_io/test/stream.hpp>
16+
#include <boost/asio/bind_immediate_executor.hpp>
1317
#include <boost/asio/io_context.hpp>
14-
#include <boost/asio/post.hpp>
18+
#include <boost/buffers/copy.hpp>
19+
#include <boost/buffers/make_buffer.hpp>
20+
#include <boost/rts/context.hpp>
1521

1622
#include "test_suite.hpp"
1723

1824
namespace boost {
1925
namespace http_io {
2026

21-
#if 0
22-
23-
auto read_some( Stream&, parser& );
24-
auto read_some( Stream&, parser&, DynamicBuffer& );
25-
auto read( Stream&, parser& );
26-
auto read( Stream&, parser&, DynamicBuffer& );
27-
28-
29-
//--------------------------------------------
30-
31-
read( s, p ); // read message
32-
33-
p.header(); // header
34-
p.body(); // decoded body
35-
36-
//--------------------------------------------
37-
38-
read_some( s, p ); // read header
39-
if( ! p.is_complete() )
40-
read( s, p ); // read body
41-
42-
p.header(); // header
43-
p.body(); // decoded body
44-
45-
//--------------------------------------------
46-
47-
read_some( s, p ); // read header
48-
read( s, p, b ); // read body into b
49-
50-
p.header(); // header
51-
b; // decoded body
52-
53-
//--------------------------------------------
54-
55-
read_some( s, p, b ); // read header, some body
56-
if( ! p.is_complete() )
57-
read( s, p, b ); // read body into b
58-
else
59-
// (avoid immediate completion)
60-
61-
p.header(); // header
62-
b; // decoded body
63-
64-
//--------------------------------------------
65-
66-
read_some( s, p ); // read header
67-
if( ! p.is_complete() )
68-
read( s, p, b ); // read body into b
69-
else if( ! p.body().empty() )
70-
p.append_body( b ); // not an I/O
71-
72-
p.header(); // header
73-
b; // decoded body
74-
75-
//--------------------------------------------
76-
77-
read( s, p, ec ); // read header, some body
78-
if( ec == error::buffer_full )
79-
ec = {};
80-
if( ! ec.failed() )
81-
{
82-
process( p,body() );
83-
p.discard_body();
84-
}
85-
86-
#endif
87-
8827
class read_test
8928
{
29+
core::string_view const msg =
30+
"HTTP/1.1 200 OK\r\n"
31+
"Content-Length: 3\r\n"
32+
"\r\n"
33+
"abc";
9034
public:
9135
void
92-
testRead()
36+
testAsyncReadSome()
9337
{
9438
boost::asio::io_context ioc;
95-
boost::asio::post(
96-
ioc.get_executor(),
97-
[]
39+
rts::context rts_ctx;
40+
http_proto::install_parser_service(rts_ctx, {});
41+
42+
// async_read_some completes when the parser reads
43+
// the header section of the message.
44+
{
45+
test::stream ts(ioc, msg);
46+
http_proto::response_parser pr(rts_ctx);
47+
pr.reset();
48+
pr.start();
49+
50+
// limit async_read_some for better coverage
51+
ts.read_size(1);
52+
53+
// header
54+
http_io::async_read_some(
55+
ts,
56+
pr,
57+
[&](system::error_code ec, std::size_t n)
58+
{
59+
BOOST_TEST(! ec.failed());
60+
BOOST_TEST_EQ(n, msg.size() - 3); // minus body
61+
});
62+
test::run(ioc);
63+
BOOST_TEST(pr.got_header());
64+
BOOST_TEST(! pr.is_complete());
65+
66+
// body
67+
for(auto i = 0; i < 3; i++)
9868
{
99-
});
69+
http_io::async_read_some(
70+
ts,
71+
pr,
72+
[&](system::error_code ec, std::size_t n)
73+
{
74+
BOOST_TEST(! ec.failed());
75+
BOOST_TEST_EQ(n, 1); // because of ts.read_size(1)
76+
});
77+
BOOST_TEST_EQ(test::run(ioc), 1);
78+
}
79+
BOOST_TEST(pr.is_complete());
80+
BOOST_TEST(pr.body() == "abc");
81+
}
82+
83+
// async_read_some reports stream errors
84+
{
85+
test::fail_count fc(11, asio::error::network_down);
86+
test::stream ts(ioc, fc, msg);
87+
http_proto::response_parser pr(rts_ctx);
88+
pr.reset();
89+
pr.start();
90+
91+
// limit async_read_some for better coverage
92+
ts.read_size(1);
93+
94+
bool invoked = false;
95+
http_io::async_read_some(
96+
ts,
97+
pr,
98+
[&](system::error_code ec, std::size_t n)
99+
{
100+
invoked = true;
101+
BOOST_TEST_EQ(ec, asio::error::network_down);
102+
BOOST_TEST_EQ(n, 10);
103+
});
104+
BOOST_TEST_EQ(test::run(ioc), 11);
105+
BOOST_TEST(invoked);
106+
}
107+
108+
// async_read_some reports parser errors
109+
{
110+
test::stream ts(ioc, msg);
111+
http_proto::response_parser pr(rts_ctx);
112+
pr.reset();
113+
pr.start();
114+
115+
// read header
116+
http_io::async_read_some(ts, pr, test::success_handler());
117+
BOOST_TEST(test::run(ioc));
118+
119+
// read body
120+
pr.set_body_limit(2);
121+
http_io::async_read_some(
122+
ts,
123+
pr,
124+
test::fail_handler(http_proto::error::body_too_large));
125+
BOOST_TEST(test::run(ioc));
126+
}
127+
}
128+
129+
void
130+
testAsyncReadHeader()
131+
{
132+
// currently, async_read_header and
133+
// async_read_some are identical
134+
}
135+
136+
void
137+
testAsyncRead()
138+
{
139+
boost::asio::io_context ioc;
140+
rts::context rts_ctx;
141+
http_proto::install_parser_service(rts_ctx, {});
142+
143+
// async_read completes when the parser reads
144+
// the entire message.
145+
{
146+
test::stream ts(ioc, msg);
147+
http_proto::response_parser pr(rts_ctx);
148+
pr.reset();
149+
pr.start();
150+
151+
// limit async_read_some for better coverage
152+
ts.read_size(1);
153+
154+
http_io::async_read(
155+
ts,
156+
pr,
157+
[&](system::error_code ec, std::size_t n)
158+
{
159+
BOOST_TEST(! ec.failed());
160+
BOOST_TEST_EQ(n, msg.size());
161+
});
162+
163+
test::run(ioc);
164+
165+
BOOST_TEST_EQ(ts.nread(), msg.size()); // because of ts.read_size(1)
166+
BOOST_TEST(pr.is_complete());
167+
BOOST_TEST(pr.body() == "abc");
168+
}
169+
170+
// async_read completes immediatly when
171+
// parser contains enough data
172+
{
173+
asio::post(
174+
ioc,
175+
[&]()
176+
{
177+
test::stream ts(ioc);
178+
http_proto::response_parser pr(rts_ctx);
179+
pr.reset();
180+
pr.start();
181+
182+
pr.commit(
183+
buffers::copy(
184+
pr.prepare(),
185+
buffers::const_buffer(
186+
msg.data(),
187+
msg.size())));
188+
189+
http_io::async_read(
190+
ts,
191+
pr,
192+
asio::bind_immediate_executor(
193+
ioc.get_executor(),
194+
test::success_handler()));
195+
196+
BOOST_TEST_EQ(ts.nread(), 0);
197+
BOOST_TEST(pr.is_complete());
198+
BOOST_TEST(pr.body() == "abc");
199+
});
200+
BOOST_TEST_EQ(test::run(ioc), 1);
201+
}
100202
}
101203

102204
void
103205
run()
104206
{
105-
testRead();
207+
testAsyncReadSome();
208+
testAsyncReadHeader();
209+
testAsyncRead();
106210
}
107211
};
108212

0 commit comments

Comments
 (0)