| 
1 | 1 | //  | 
2 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)  | 
 | 3 | +// Copyright (c) 2025 Mohammad Nejati  | 
3 | 4 | //  | 
4 | 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying  | 
5 | 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)  | 
 | 
10 | 11 | // Test that header file is self-contained.  | 
11 | 12 | #include <boost/beast2/read.hpp>  | 
12 | 13 | 
 
  | 
 | 14 | +#include <boost/beast2/test/stream.hpp>  | 
 | 15 | +#include <boost/asio/bind_immediate_executor.hpp>  | 
13 | 16 | #include <boost/asio/io_context.hpp>  | 
14 |  | -#include <boost/asio/post.hpp>  | 
 | 17 | +#include <boost/buffers/copy.hpp>  | 
 | 18 | +#include <boost/buffers/make_buffer.hpp>  | 
 | 19 | +#include <boost/rts/context.hpp>  | 
15 | 20 | 
 
  | 
16 |  | -#include "test_suite.hpp"  | 
 | 21 | +#include "test_helpers.hpp"  | 
17 | 22 | 
 
  | 
18 | 23 | namespace boost {  | 
19 | 24 | namespace beast2 {  | 
20 | 25 | 
 
  | 
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 |  | - | 
88 | 26 | class read_test  | 
89 | 27 | {  | 
 | 28 | +    core::string_view const msg =  | 
 | 29 | +        "HTTP/1.1 200 OK\r\n"  | 
 | 30 | +        "Content-Length: 3\r\n"  | 
 | 31 | +        "\r\n"  | 
 | 32 | +        "abc";  | 
90 | 33 | public:  | 
91 | 34 |     void  | 
92 |  | -    testRead()  | 
 | 35 | +    testAsyncReadSome()  | 
93 | 36 |     {  | 
94 | 37 |         boost::asio::io_context ioc;  | 
95 |  | -        boost::asio::post(  | 
96 |  | -            ioc.get_executor(),  | 
97 |  | -            []  | 
 | 38 | +        rts::context rts_ctx;  | 
 | 39 | +        http_proto::install_parser_service(rts_ctx, {});  | 
 | 40 | + | 
 | 41 | +        // async_read_some completes when the parser reads  | 
 | 42 | +        // the header section of the message.  | 
 | 43 | +        {  | 
 | 44 | +            test::stream ts(ioc, msg);  | 
 | 45 | +            http_proto::response_parser pr(rts_ctx);  | 
 | 46 | +            pr.reset();  | 
 | 47 | +            pr.start();  | 
 | 48 | + | 
 | 49 | +            // limit async_read_some for better coverage  | 
 | 50 | +            ts.read_size(1);  | 
 | 51 | + | 
 | 52 | +            // header  | 
 | 53 | +            async_read_some(  | 
 | 54 | +                ts,  | 
 | 55 | +                pr,  | 
 | 56 | +                [&](system::error_code ec, std::size_t n)  | 
 | 57 | +                {  | 
 | 58 | +                    BOOST_TEST(! ec.failed());  | 
 | 59 | +                    BOOST_TEST_EQ(n, msg.size() - 3); // minus body  | 
 | 60 | +                });  | 
 | 61 | +            test::run(ioc);  | 
 | 62 | +            BOOST_TEST(pr.got_header());  | 
 | 63 | +            BOOST_TEST(! pr.is_complete());  | 
 | 64 | + | 
 | 65 | +            // body  | 
 | 66 | +            for(auto i = 0; i < 3; i++)  | 
98 | 67 |             {  | 
99 |  | -            });  | 
 | 68 | +                async_read_some(  | 
 | 69 | +                    ts,  | 
 | 70 | +                    pr,  | 
 | 71 | +                    [&](system::error_code ec, std::size_t n)  | 
 | 72 | +                    {  | 
 | 73 | +                        BOOST_TEST(! ec.failed());  | 
 | 74 | +                        BOOST_TEST_EQ(n, 1); // because of ts.read_size(1)  | 
 | 75 | +                    });  | 
 | 76 | +                BOOST_TEST_EQ(test::run(ioc), 1);  | 
 | 77 | +            }  | 
 | 78 | +            BOOST_TEST(pr.is_complete());  | 
 | 79 | +            BOOST_TEST(pr.body() == "abc");  | 
 | 80 | +        }  | 
 | 81 | + | 
 | 82 | +        // async_read_some reports stream errors  | 
 | 83 | +        {  | 
 | 84 | +            test::fail_count fc(11, asio::error::network_down);  | 
 | 85 | +            test::stream ts(ioc, fc, msg);  | 
 | 86 | +            http_proto::response_parser pr(rts_ctx);  | 
 | 87 | +            pr.reset();  | 
 | 88 | +            pr.start();  | 
 | 89 | + | 
 | 90 | +            // limit async_read_some for better coverage  | 
 | 91 | +            ts.read_size(1);  | 
 | 92 | + | 
 | 93 | +            bool invoked = false;  | 
 | 94 | +            async_read_some(  | 
 | 95 | +                ts,  | 
 | 96 | +                pr,  | 
 | 97 | +                [&](system::error_code ec, std::size_t n)  | 
 | 98 | +                {  | 
 | 99 | +                    invoked = true;  | 
 | 100 | +                    BOOST_TEST_EQ(ec, asio::error::network_down);  | 
 | 101 | +                    BOOST_TEST_EQ(n, 10);  | 
 | 102 | +                });  | 
 | 103 | +            BOOST_TEST_EQ(test::run(ioc), 11);  | 
 | 104 | +            BOOST_TEST(invoked);  | 
 | 105 | +        }  | 
 | 106 | + | 
 | 107 | +        // async_read_some reports parser errors  | 
 | 108 | +        {  | 
 | 109 | +            test::stream ts(ioc, msg);  | 
 | 110 | +            http_proto::response_parser pr(rts_ctx);  | 
 | 111 | +            pr.reset();  | 
 | 112 | +            pr.start();  | 
 | 113 | + | 
 | 114 | +            // read header  | 
 | 115 | +            async_read_some(ts, pr, test::success_handler());  | 
 | 116 | +            test::run(ioc);  | 
 | 117 | + | 
 | 118 | +            // read body  | 
 | 119 | +            pr.set_body_limit(2);  | 
 | 120 | +            async_read_some(  | 
 | 121 | +                ts,  | 
 | 122 | +                pr,  | 
 | 123 | +                test::fail_handler(http_proto::error::body_too_large));  | 
 | 124 | +            test::run(ioc);  | 
 | 125 | +        }  | 
 | 126 | +    }  | 
 | 127 | + | 
 | 128 | +    void  | 
 | 129 | +    testAsyncReadHeader()  | 
 | 130 | +    {  | 
 | 131 | +        // currently, async_read_header and  | 
 | 132 | +        // async_read_some are identical  | 
 | 133 | +    }  | 
 | 134 | + | 
 | 135 | +    void  | 
 | 136 | +    testAsyncRead()  | 
 | 137 | +    {  | 
 | 138 | +        boost::asio::io_context ioc;  | 
 | 139 | +        rts::context rts_ctx;  | 
 | 140 | +        http_proto::install_parser_service(rts_ctx, {});  | 
 | 141 | + | 
 | 142 | +        // async_read completes when the parser reads  | 
 | 143 | +        // the entire message.  | 
 | 144 | +        {  | 
 | 145 | +            test::stream ts(ioc, msg);  | 
 | 146 | +            http_proto::response_parser pr(rts_ctx);  | 
 | 147 | +            pr.reset();  | 
 | 148 | +            pr.start();  | 
 | 149 | + | 
 | 150 | +            // limit async_read_some for better coverage  | 
 | 151 | +            ts.read_size(1);  | 
 | 152 | + | 
 | 153 | +            async_read(  | 
 | 154 | +                ts,  | 
 | 155 | +                pr,  | 
 | 156 | +                [&](system::error_code ec, std::size_t n)  | 
 | 157 | +                {  | 
 | 158 | +                    BOOST_TEST(! ec.failed());  | 
 | 159 | +                    BOOST_TEST_EQ(n, msg.size());  | 
 | 160 | +                });  | 
 | 161 | + | 
 | 162 | +            test::run(ioc);  | 
 | 163 | + | 
 | 164 | +            BOOST_TEST_EQ(ts.nread(), msg.size()); // because of ts.read_size(1)  | 
 | 165 | +            BOOST_TEST(pr.is_complete());  | 
 | 166 | +            BOOST_TEST(pr.body() == "abc");  | 
 | 167 | +        }  | 
 | 168 | + | 
 | 169 | +        // async_read completes immediatly when  | 
 | 170 | +        // parser contains enough data  | 
 | 171 | +        {  | 
 | 172 | +            asio::post(  | 
 | 173 | +                ioc,  | 
 | 174 | +                [&]()  | 
 | 175 | +                {  | 
 | 176 | +                    test::stream ts(ioc);  | 
 | 177 | +                    http_proto::response_parser pr(rts_ctx);  | 
 | 178 | +                    pr.reset();  | 
 | 179 | +                    pr.start();  | 
 | 180 | + | 
 | 181 | +                    pr.commit(  | 
 | 182 | +                        buffers::copy(  | 
 | 183 | +                            pr.prepare(),  | 
 | 184 | +                            buffers::const_buffer(  | 
 | 185 | +                                msg.data(),  | 
 | 186 | +                                msg.size())));  | 
 | 187 | + | 
 | 188 | +                    async_read(  | 
 | 189 | +                        ts,  | 
 | 190 | +                        pr,  | 
 | 191 | +                        asio::bind_immediate_executor(  | 
 | 192 | +                            ioc.get_executor(),  | 
 | 193 | +                            test::success_handler()));  | 
 | 194 | + | 
 | 195 | +                    BOOST_TEST_EQ(ts.nread(), 0);  | 
 | 196 | +                    BOOST_TEST(pr.is_complete());  | 
 | 197 | +                    BOOST_TEST(pr.body() == "abc");  | 
 | 198 | +                });  | 
 | 199 | +            BOOST_TEST_EQ(test::run(ioc), 1);  | 
 | 200 | +        }  | 
100 | 201 |     }  | 
101 | 202 | 
 
  | 
102 | 203 |     void  | 
103 | 204 |     run()  | 
104 | 205 |     {  | 
105 |  | -        testRead();  | 
 | 206 | +        testAsyncReadSome();  | 
 | 207 | +        testAsyncReadHeader();  | 
 | 208 | +        testAsyncRead();  | 
106 | 209 |     }  | 
107 | 210 | };  | 
108 | 211 | 
 
  | 
 | 
0 commit comments