1  
//
1  
//
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3  
// Copyright (c) 2024 Christian Mazakas
3  
// Copyright (c) 2024 Christian Mazakas
4  
// Copyright (c) 2025 Mohammad Nejati
4  
// Copyright (c) 2025 Mohammad Nejati
5  
//
5  
//
6  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
6  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
7  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8  
//
8  
//
9  
// Official repository: https://github.com/cppalliance/http
9  
// Official repository: https://github.com/cppalliance/http
10  
//
10  
//
11  

11  

12  
#include <boost/http/request_base.hpp>
12  
#include <boost/http/request_base.hpp>
13  

13  

14  
#include <cstring>
14  
#include <cstring>
15  

15  

16  
namespace boost {
16  
namespace boost {
17  
namespace http {
17  
namespace http {
18  

18  

19  
void
19  
void
20  
request_base::
20  
request_base::
21  
set_expect_100_continue(bool b)
21  
set_expect_100_continue(bool b)
22  
{
22  
{
23  
    if(h_.md.expect.count == 0)
23  
    if(h_.md.expect.count == 0)
24  
    {
24  
    {
25  
        BOOST_ASSERT(
25  
        BOOST_ASSERT(
26  
            ! h_.md.expect.ec);
26  
            ! h_.md.expect.ec);
27  
        BOOST_ASSERT(
27  
        BOOST_ASSERT(
28  
            ! h_.md.expect.is_100_continue);
28  
            ! h_.md.expect.is_100_continue);
29  
        if( b )
29  
        if( b )
30  
        {
30  
        {
31  
            append(
31  
            append(
32  
                field::expect,
32  
                field::expect,
33  
                "100-continue");
33  
                "100-continue");
34  
            return;
34  
            return;
35  
        }
35  
        }
36  
        return;
36  
        return;
37  
    }
37  
    }
38  

38  

39  
    if(h_.md.expect.count == 1)
39  
    if(h_.md.expect.count == 1)
40  
    {
40  
    {
41  
        if(b)
41  
        if(b)
42  
        {
42  
        {
43  
            if(! h_.md.expect.ec)
43  
            if(! h_.md.expect.ec)
44  
            {
44  
            {
45  
                BOOST_ASSERT(
45  
                BOOST_ASSERT(
46  
                    h_.md.expect.is_100_continue);
46  
                    h_.md.expect.is_100_continue);
47  
                return;
47  
                return;
48  
            }
48  
            }
49  
            BOOST_ASSERT(
49  
            BOOST_ASSERT(
50  
                ! h_.md.expect.is_100_continue);
50  
                ! h_.md.expect.is_100_continue);
51  
            auto it = find(field::expect);
51  
            auto it = find(field::expect);
52  
            BOOST_ASSERT(it != end());
52  
            BOOST_ASSERT(it != end());
53  
            set(it, "100-continue");
53  
            set(it, "100-continue");
54  
            return;
54  
            return;
55  
        }
55  
        }
56  

56  

57  
        auto it = find(field::expect);
57  
        auto it = find(field::expect);
58  
        BOOST_ASSERT(it != end());
58  
        BOOST_ASSERT(it != end());
59  
        erase(it);
59  
        erase(it);
60  
        return;
60  
        return;
61  
    }
61  
    }
62  

62  

63  
    BOOST_ASSERT(h_.md.expect.ec);
63  
    BOOST_ASSERT(h_.md.expect.ec);
64  

64  

65  
    auto nc = (b ? 1 : 0);
65  
    auto nc = (b ? 1 : 0);
66  
    auto ne = h_.md.expect.count - nc;
66  
    auto ne = h_.md.expect.count - nc;
67  
    if( b )
67  
    if( b )
68  
        set(find(field::expect), "100-continue");
68  
        set(find(field::expect), "100-continue");
69  

69  

70  
    raw_erase_n(field::expect, ne);
70  
    raw_erase_n(field::expect, ne);
71  
    h_.md.expect.count = nc;
71  
    h_.md.expect.count = nc;
72  
    h_.md.expect.ec = {};
72  
    h_.md.expect.ec = {};
73  
    h_.md.expect.is_100_continue = b;
73  
    h_.md.expect.is_100_continue = b;
74  
}
74  
}
75  

75  

76  
//------------------------------------------------
76  
//------------------------------------------------
77  

77  

78  
void
78  
void
79  
request_base::
79  
request_base::
80  
set_start_line_impl(
80  
set_start_line_impl(
81  
    http::method m,
81  
    http::method m,
82  
    core::string_view ms,
82  
    core::string_view ms,
83  
    core::string_view t,
83  
    core::string_view t,
84  
    http::version v)
84  
    http::version v)
85  
{
85  
{
86  
    // TODO: check validity
86  
    // TODO: check validity
87  
    auto const vs = to_string(v);
87  
    auto const vs = to_string(v);
88  
    auto const new_prefix =
88  
    auto const new_prefix =
89  
        ms.size() + 1 + // method SP
89  
        ms.size() + 1 + // method SP
90  
        t.size() + 1 +  // request-target SP
90  
        t.size() + 1 +  // request-target SP
91  
        vs.size() + 2;  // HTTP-version CRLF
91  
        vs.size() + 2;  // HTTP-version CRLF
92  

92  

93  
    // Introduce a new scope so that prefix_op's
93  
    // Introduce a new scope so that prefix_op's
94  
    // destructor runs before h_.on_start_line().
94  
    // destructor runs before h_.on_start_line().
95  
    {
95  
    {
96  
        auto op = prefix_op_t(
96  
        auto op = prefix_op_t(
97  
            *this, new_prefix, &ms, &t);
97  
            *this, new_prefix, &ms, &t);
98  

98  

99  
        h_.version = v;
99  
        h_.version = v;
100  
        h_.req.method = m;
100  
        h_.req.method = m;
101  
        h_.req.method_len = static_cast<
101  
        h_.req.method_len = static_cast<
102  
            offset_type>(ms.size());
102  
            offset_type>(ms.size());
103  
        h_.req.target_len = static_cast<
103  
        h_.req.target_len = static_cast<
104  
            offset_type>(t.size());
104  
            offset_type>(t.size());
105  

105  

106  
        char* m_dest = h_.buf;
106  
        char* m_dest = h_.buf;
107  
        char* t_dest = h_.buf + ms.size() + 1;
107  
        char* t_dest = h_.buf + ms.size() + 1;
108  
        char* v_dest = t_dest + t.size() + 1;
108  
        char* v_dest = t_dest + t.size() + 1;
109  

109  

110  
        std::memmove(t_dest, t.data(), t.size());
110  
        std::memmove(t_dest, t.data(), t.size());
111  
        t_dest[t.size()] = ' ';
111  
        t_dest[t.size()] = ' ';
112  

112  

113  
        // memmove after target because could overlap
113  
        // memmove after target because could overlap
114  
        std::memmove(m_dest, ms.data(), ms.size());
114  
        std::memmove(m_dest, ms.data(), ms.size());
115  
        m_dest[ms.size()] = ' ';
115  
        m_dest[ms.size()] = ' ';
116  

116  

117  
        std::memcpy(v_dest, vs.data(), vs.size());
117  
        std::memcpy(v_dest, vs.data(), vs.size());
118  
        v_dest[vs.size() + 0] = '\r';
118  
        v_dest[vs.size() + 0] = '\r';
119  
        v_dest[vs.size() + 1] = '\n';
119  
        v_dest[vs.size() + 1] = '\n';
120  
    }
120  
    }
121  

121  

122  
    h_.on_start_line();
122  
    h_.on_start_line();
123  
}
123  
}
124  

124  

125  
} // http
125  
} // http
126  
} // boost
126  
} // boost