1  
//
1  
//
2  
// Copyright (c) 2025 Mohammad Nejati
2  
// Copyright (c) 2025 Mohammad Nejati
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/http
7  
// Official repository: https://github.com/cppalliance/http
8  
//
8  
//
9  

9  

10  
#include <boost/http/response_base.hpp>
10  
#include <boost/http/response_base.hpp>
11  

11  

12  
#include <cstring>
12  
#include <cstring>
13  

13  

14  
namespace boost {
14  
namespace boost {
15  
namespace http {
15  
namespace http {
16  

16  

17  
void
17  
void
18  
response_base::
18  
response_base::
19  
set_start_line_impl(
19  
set_start_line_impl(
20  
    http::status sc,
20  
    http::status sc,
21  
    unsigned short si,
21  
    unsigned short si,
22  
    core::string_view rs,
22  
    core::string_view rs,
23  
    http::version v)
23  
    http::version v)
24  
{
24  
{
25  
    // TODO: check validity
25  
    // TODO: check validity
26  
    auto const vs = to_string(v);
26  
    auto const vs = to_string(v);
27  
    auto const new_prefix =
27  
    auto const new_prefix =
28  
        vs.size() + 1 + // HTTP-version SP
28  
        vs.size() + 1 + // HTTP-version SP
29  
        3 + 1 +         // status-code SP
29  
        3 + 1 +         // status-code SP
30  
        rs.size() + 2;  // reason-phrase CRLF
30  
        rs.size() + 2;  // reason-phrase CRLF
31  

31  

32  
    // Introduce a new scope so that prefix_op's
32  
    // Introduce a new scope so that prefix_op's
33  
    // destructor runs before h_.on_start_line().
33  
    // destructor runs before h_.on_start_line().
34  
    {
34  
    {
35  
        auto op = prefix_op_t(*this, new_prefix, &rs);
35  
        auto op = prefix_op_t(*this, new_prefix, &rs);
36  
        char* dest = h_.buf;
36  
        char* dest = h_.buf;
37  

37  

38  
        h_.version = v;
38  
        h_.version = v;
39  
        vs.copy(dest, vs.size());
39  
        vs.copy(dest, vs.size());
40  
        dest += vs.size();
40  
        dest += vs.size();
41  
        *dest++ = ' ';
41  
        *dest++ = ' ';
42  

42  

43  
        h_.res.status = sc;
43  
        h_.res.status = sc;
44  
        h_.res.status_int = si;
44  
        h_.res.status_int = si;
45  
        dest[0] = '0' + ((h_.res.status_int / 100) % 10);
45  
        dest[0] = '0' + ((h_.res.status_int / 100) % 10);
46  
        dest[1] = '0' + ((h_.res.status_int /  10) % 10);
46  
        dest[1] = '0' + ((h_.res.status_int /  10) % 10);
47  
        dest[2] = '0' + ((h_.res.status_int /   1) % 10);
47  
        dest[2] = '0' + ((h_.res.status_int /   1) % 10);
48  
        dest[3] = ' ';
48  
        dest[3] = ' ';
49  
        dest += 4;
49  
        dest += 4;
50  

50  

51  
        std::memmove(dest, rs.data(), rs.size());
51  
        std::memmove(dest, rs.data(), rs.size());
52  
        dest += rs.size();
52  
        dest += rs.size();
53  
        dest[0] = '\r';
53  
        dest[0] = '\r';
54  
        dest[1] = '\n';
54  
        dest[1] = '\n';
55  
    }
55  
    }
56  

56  

57  
    h_.on_start_line();
57  
    h_.on_start_line();
58  
}
58  
}
59  

59  

60  
void
60  
void
61  
response_base::
61  
response_base::
62  
set_version(
62  
set_version(
63  
    http::version v)
63  
    http::version v)
64  
{
64  
{
65  
    if(v == h_.version)
65  
    if(v == h_.version)
66  
        return;
66  
        return;
67  
    if(h_.is_default())
67  
    if(h_.is_default())
68  
    {
68  
    {
69  
        auto def = h_.get_default(detail::kind::response);
69  
        auto def = h_.get_default(detail::kind::response);
70  
        return set_start_line_impl(
70  
        return set_start_line_impl(
71  
            def->res.status, def->res.status_int,
71  
            def->res.status, def->res.status_int,
72  
            core::string_view(
72  
            core::string_view(
73  
                def->cbuf + 13, def->prefix - 15), v);
73  
                def->cbuf + 13, def->prefix - 15), v);
74  
    }
74  
    }
75  

75  

76  
    // Introduce a new scope so that prefix_op's
76  
    // Introduce a new scope so that prefix_op's
77  
    // destructor runs before h_.on_start_line().
77  
    // destructor runs before h_.on_start_line().
78  
    {
78  
    {
79  
        auto op = prefix_op_t(
79  
        auto op = prefix_op_t(
80  
            *this, h_.prefix, nullptr);
80  
            *this, h_.prefix, nullptr);
81  
        char* dest = h_.buf;
81  
        char* dest = h_.buf;
82  
        if(v == http::version::http_1_1)
82  
        if(v == http::version::http_1_1)
83  
            dest[7] = '1';
83  
            dest[7] = '1';
84  
        else
84  
        else
85  
            dest[7] = '0';
85  
            dest[7] = '0';
86  
        h_.version = v;
86  
        h_.version = v;
87  
    }
87  
    }
88  

88  

89  
    h_.on_start_line();
89  
    h_.on_start_line();
90  
}
90  
}
91  

91  

92  
} // http
92  
} // http
93  
} // boost
93  
} // boost